타입스크립트를 처음 접했을 때 가장 어려웠던 부분 중 하나는 '언제 타입을 명시적으로 선언하고, 언제 추론된 타입을 이용해야하는지' 판단할 수 없는 것이었다.
명시적인 타입구문은 대부분 필요하지 않다. 타입 추론이 된다면 불필요한 타입은 가독성을 해치고 오히려 방해가 될 뿐이다. 만약 타입을 확신하지 못한다면 에디터를 통해 체크하면 된다.
// AS-IS
let name: string = 'koo'
// TO-BE
let name = 'koo'
// AS-IS
const name: string = 'koo'
// name: string
// TO-BE
const name = 'koo'
// name: 'koo'
아래와 같은 코드가 있을때 content
가 number
타입도 들어올 수 있게 되면, Data
인터페이스와 log
함수 둘 다 수정해야한다.
// AS-IS
interface Data {
date: string,
content: string,
}
function log(data: Data) {
let date: string = data.date
let content: string = data.content
}
추론을 사용하여 유연하게 대응하자.
// TO-BE
interface Data {
date: string,
content: string | number ,
}
function log({date, content}: Data) { ... }
이상적인 타입스크립트 코드는 함수 시그니처에 타입 구문을 포함한다. 단, 기본값이 있는 경우 생략하기도 한다.
function parseNumber(string: string, base=10) { ... }
함수의 리턴값을 명시해주면 함수를 작성할때 리턴값을 잘못 반환하는 오류를 줄일 수 있다.
const cache: {[key:string]: number} = {}
function getData(key: string): Promise<number> {
if(cache[key]) {
return cache[key]
// type 'number' is not assignable to type 'Promise<number>'
}
return fetch(`/api?key=${key}`)
.then(res => res.json())
.then(data => {
cache[key] = data
return data
})
}
객체 리터럴에 타입을 명시하면 잉여 속성 체크 가 동작하므로 타입의 오타를 잡는데 효과적이다.
interface Product { name: string, price:number }
const product: Product = {
name: 'computer',
price: 10000
barcode: '100010010' // 'barcode' does not exist in type 'Product'
}