타입스크립트 코드를 실행한다는 것은, 엄밀히 말해 타입스크립트 컴파일러가 생성한 자바스크립트 코드를 실행하는 것이다. 이러한 것은 디버깅이 필요한 시점에 깨닫게 된다. 디버깅 시점의 변환된 JS 코드는 복잡해서 디버깅이 어렵다. 그렇기 때문에 소스맵(source)
이라는 해결책이 나왔다. 소스맵은 변환된 코드의 위치와 심벌을 원본 코드에 매핑한다.
타입스크립트가 소스맵을 생성하게 하려면 tsconfig.json
에서 sourceMap
옵션을 설정해야 한다.
{
"compileOptions":{
"sourceMap" : true
}
}
이렇게 설정 후 컴파일하면 .ts
파일에 대해서 .js
와 .js.map
두 개의 파일이 생성된다.
타입스크립트는 타입 체크 기능 외에 타입스크립트 코드를 특정 버전 JS로 컴파일하는 기능이 있다. 그래서 타입스크립트 컴파일러를 트랜스파일러(transpiler)로 활용하는 것도 가능하다. TS로 마이그레이션 할 때, 막막하다면 옛날 버전의 JS를 최신 버전이 JS로 바꾸는 작업부터 시작하면 된다. 타입스크립트를 도입할 때 모던 자바스크립트(ES6)의 기능을 아는 것은 도움이 된다.
ES2015 이전에는 코드를 개별 모듈로 분할하는 방법이 없었지만 import
와 export
가 표준이 되었다. 마이그레이션 대상이 비표준 모듈 시스템을 사용 중이라면 전환하는 것이 필수적이다.
과거에는 프로토타입 기반 객체 모델을 사용했지만, ES2015에서는 프로토타입 모델보다는 클래스 기반 모델을 사용한다.
하지만 최근에는 클래스 문법도 많이 사용되지 않고 함수 컴포넌트가 많이 사용되는 추세이다.
var
키워드의 스코프 규칙에 문제가 있기 때문에 let
과 const
를 사용하면 스코프 문제를 피할 수 있다.
과거에는 for
루프를 많이 사용했지만, 모던 JS에는 for-of
루프가 존재한다. for-of
루프는 코드가 짧고 인덱스 변수를 사용하지 않아서 실수를 줄일 수 있다. 인덱스가 필요할 땐, forEach
를 사용하는 것이 좋다. for-in
의 경우는 몇가지 문제가 있어서 사용하지 않는 것이 좋다.
this
키워드는 일반적인 변수들과는 다른 스코프 규칙을 가지기 때문에, JS에서는 가장 어려운 개념 중 하나이다. 이 때 화살표 함수를 사용하면 상위 스코프의 this
를 유지할 수 있다. 인라인에서는 일반 함수보다 화살표 함수가 더 직관적이고 코드도 간결해지기 때문에 가급적 화살표 함수를 사용하는 것이 좋다. 컴파일러 옵션에 noImplicitThis
를 설정하면 타입스크립트가 this
바인딩 관련된 오류를 표시해주므로 설정하는 것이 좋다.
변수와 객체 속성의 이름이 같으면 const pt = {x,y,z}
와 같이 표현 가능하다. 이런 것을 단축 객체 표현(compact object literal)이라고 한다. 이 반대는 객체 구조 분해(object destructuring)이다.
declare let obj: { props: { a: string; b: number } }
const props = obj.props
const a = props.a
const b = props.b
declare let obj: { props: { a: string; b: number } }
const { props } = obj
const { a, b } = props
구조 분해 문법은 위와 같이 사용하고 기본 값을 지정할 수도 있다.
declare let obj: { props: { a: string; b: number } }
const { a = 'default' } = obj.props
배열도 동일하게 구조 문해 문법을 사용할 수 있다. 매개변수도 또한 가능하다.
declare let obj: { props: { a: string; b: number } }
const point = [1, 2, 3]
const [x, y, z] = point
const [, a, b] = point // Ignore the first one
declare let obj: { props: { a: string; b: number } }
const points = [
[1, 2, 3],
[4, 5, 6],
]
points.forEach(([x, y, z]) => console.log(x + y + z))
// Logs 6, 15
함수의 모든 매개변수는 선택적(생략 가능)이며, 매개변수를 지정하지 않으면 undefined
로 간주된다. 모던 JS에서는 매개변수에 기본값을 직접 지정할 수 있다. 매개변수에 기본 값을 지정하면 코드가 간결해지고 base
가 선택적 매개변수라는 것을 명확히 나타낼 수 있다.
function parseNum(str, base = 10) {
return parseInt(str, base)
}
async와 await를 사용하면 코드가 간결해져서 실수를 방지할 수 있고, 비동기 코드에 타입 정보가 전달되어 타입 추론이 가능해진다.
function getJSON(url: string) {
return fetch(url).then(response => response.json())
}
function getJSONCallback(url: string, cb: (result: unknown) => void) {
// ...
}
async function getJSON(url: string) {
const response = await fetch(url)
return response.json()
}
인덱스 시그니처는 편리하지만 몇 가지 문제가 있다. 특정 문자열이 주어질 때, 원치 않는 값과 타입을 받을 수 있기 때문에, 이런 문제를 방지하기 위해 Map
을 사용하는 것이 좋다.
function countWordMap(text: string) {
const counts = new Map<string, number>()
for (const word of text.split(/[\s,.]+/)) {
counts.set(word, 1 + (counts.get(word) || 0))
}
return counts
}
use strict
넣지 않기ES5 에서는 버그가 될 수 있는 코드 패턴에 오류를 표시해주는 엄격 모드(strict mode)가 도입되었는데 코드의 제일 처음에 'use strict'
와 같이 표시하면 활성화 된다. 하지만 TS에서는 훨씬 더 엄격한 체크를 하기 때문에 굳이 쓸 필요가 없다.
@ts-check
지시자를 사용하면 타입스크립트 전환시에 어떤 문제가 발생하는지 미리 알 수 있다. 하지만 이 지시자는 매우 느슨한 수준으로 타입 체크를 수행하고, 심지어 noImplicitAny
설정을 해제한 것보다 헐거운 체크를 수행한다.
// @ts-check
const person = { first: 'Grace', last: 'Hopper' }
2 * person.first
// ~~~~~~~~~~~~ The right-hand side of an arithmetic operation must be of type
// 'any', 'number', 'bigint', or an enum type
@ts-check
지시자를 통해 타입 불일치나 함수의 매개변수 개수 불일치 같은 간단한 오류 외에도 아래와 같은 오류들을 찾아낼 수 있다.
변수를 선언할 때 보통은 let
이나 const
를 사용하지만 어딘가에 숨어있는 변수(HTML파일내의