Item19: 추론 가능한 타입을 사용해 장황한 코드 방지하기
TS는 어느정도 타입추론이 되기때문에 TS의 많은 타입 구문은 사실 불필요함
타입 추론이 가능하더라도, 구현상의 오류가 함수를 호출한 곳 까지 영향을 미치지 않도록 하기 위해 함숭 타입 구문을 명시하는 것도 좋다
Item20: 다른 타입에는 다른 변수 사용하기
자바스크립트에서는 한 변수를 다른 목적을 가지는 다른 타입으로 재사용해도 된다.
하지만, 타입스크립트에서는 오류를 발생한다.
자바스크립트에서는 한 변수를 다른 타입으로 재사용해도 되지만, 타입스크립트에서는 오류를 발생한다.
let id = "12-34-56";
fetchProdiuct(id); // string인 id
id = 123456;
fetchProductBySErialNumber(id) // number인 id
javascript에서는 잘 동작한다.
let id = "12-34-56";
fetchProdiuct(id);
id = 123456;
// ~~ '123456' 형식은 'string'형식에 할당할 수 없습니다. (오류발생)
fetchProductBySErialNumber(id);
// ~~ 'string' 형식의 인수는 'number' 형식의 매개변수에 할당될 수 없습니다.
다만, typescript에서는 id는 string으로 타입을 추론하였기 때문에, let으로 number type로 변경을 했어도, 타입이 변하지 않는 것을 확인할 수 있다.
let id: string|number = '12-34-56';
fetchProduct(id);
id = 123456;
fetchProductBySerialNumber(id);
위와 같이 string과 number를 모두 포함할 수 있도록 유니온 타입으로 확장하면 에러 없이 정상적으로 작동한다.
하지만, 위와 같이 코드를 짤 경우 많은 문제가 생길 수 있다.
id를 사용할 때마다 값의 타입이 무엇인지 확인이 필요하므로, 별도의 변수를 도입하는 것이 좋다.
const id = "12-34-56";
fetchProduct(id);
const serial = 123456;
fetchProductBySerialNumber(serial);
다른 타입에는 별도의 변수를 사용하는 것이 바람직한 이유는?
- 서로 관련이 없는 두 개의 값을 분리한다. (id, serial)
- 변수명을 더 구체적으로 지을 수 있다.
- 타입 추론을 향상시키며, 타입 구문이 불필요해진다.
- 타입이 좀 더 간결해진다.
- let 대신 const로 변수를 선언하게 된다. const는 코드가 간결해지고, 타입 체커가 타입을 추론하기에 좋다.
Item21: 타입 넓히기
런타임에 모든 변수는 유일한 값을 가진다.
타입스크립트가 작성된 코드를 체크하는 정적 분석 시점에, 변수는 ‘가능한’ 값들의 집합인 타입
지정된 단일 값을 가지고 할당 가능한 값들의 집합을 유추해야 하는 것을 타입 넓히기
넓히기의 과정을 이해한다면 오류의 원인을파악하고타입구문을더 효과적으로 사용할 수 있다.
타입넓히기를 제어하는 방법
- 명시적 타입 구문을 제공하기
- 타입 체커에 추가적인 문맥을 제공하기
- const 단언문인 as const를 사용하기
Item22: 타입 좁히기
타입스크립트가 넓은 타입으로부터 좁은 타입으로 진행하는 과정
가장 일반적인 예시 - null 체크
const el = document.getElementById('foo'); // 타입이 HTMLElement | null
if (!el) throw new Error('Unable to find #foo');
el; // 타입은 HTMLElement
el.innerHTML = 'party Time'.blink();
추가적인 타입을 좁히는 방법은 다음과 같다.
- 에러 throw
- instanceof
- in 연산자
- 명시적 ‘태그’ 붙이기
- 사용자 정의 타입 가드
Item23: 한꺼번에 객체 생성하기
객체를 생성할 때, 프로퍼티를 하나씩 추가하는 것보다 필요한 프로퍼티 모두를 한번에 객체에 넣어 생성하는 것이 타입추론에 더좋다.
객체들을 반드시 제각각나눠서 만들어야 한다면, 타입 단언문을 사용해 타입체커를 통과하게 할 수 있다.
const pt = {} as Point;
px.x = 3;
px.y = 4;
객체 전개 연산자를 사용하여 한꺼번에 큰 객체를 만들어낼 수 있다.
- 타입에 안전한 방식으로 조건부 속성을 추가하려면, 속성을 추가하지 않는 null 또는 {}으로 객체 전개를 사용하면 된다.
function addOptional<T extends object, U extends object>(
a: T, b: U | null
): T & Partial<U> {
return {...a, ...b};
}
const pharaoh = addOptional(
nameTitle,
hasDates ? {start: -2589, end: -2566| : null
);
pharaoh.start // 타입 number | undefined
- 헬퍼함수를 사용하여 선택적필드를 포함하는 새로운 객체 생성할 수 있다.
Item24: 일관성 있는별칭 사용하기
별칭을 남발해서 사용하면 제어 흐름을 분석하기 어렵다.
function isPointInPolygon(polygon: Polygon, pt: Coordinate) {
const box = polygon.bbox;
if (box) {
if(pt.x < box.x[0] || pt.x > box.x[1] ||
pt.y < box.y[0] || pt.y > box.y[1]) {
return false;
}
}
}
위 코드는 bbox, box라는 서로 다른 이름이 사용되고 있다.
일관된 이름을 사용하기 위해서는 구조분해 할당을 사용하는 것이좋다.
별칭은 타입스크립트가 타입을 좁히는 것을 방해한다. 변수에 별칭을 사용할때는 일관되게 사용할 것을 명심하자
Item25: 비동기 코드에는 콜백 대신 async 함수사용하기
자바스크립트로 비동기 로직을 처리할 때는 콜백함수, promise, async / await이 있다.
콜백보다는 프로미스 및 async / await을 사용하는 것이 코드 작성과 타입 추론면에서 유리하다.
어떤 함수가 프로미스를 반환한다면 async로 선언하는 것이 좋다.
Item26: 타입 추론에 문맥이 어떻게 사용되는지 이해하기
타입스크립트는 타입을 추론할 때 단순히 값만 고려하지 않는다.
값이 존재하는 곳의 문맥도 살핀다.
any를 사용하지 않고 오류를 고칠 수 있는 또 다른 방법은 ‘상수 문맥’ 을 제공하는 것이다.
타입 추론에서 문맥이 어떻게 어떻게 쓰이는지 주의해서 살펴봐야한다.
변수를 뽑아서 별도로 선언했을 때 오류가 발생한다면 타입 선언을 추가해야한다.
변수가 정말로 상수라면 상수 단언을 사용해야한다.
그러나 상수단언을 사용하면 정의한 곳이 아니라 사용한 곳에서 오류가 발생하므로 주의해야한다.
Item27: 함수형 기법과 라이브러리로 타입 흐름 유지하기
타입흐름을 개선하고, 가독성을 높이고, 명시적인 타입 구문의 필요성을 줄이기 위해서는 유틸리티 라이브러리를 이용하는 것도 좋은 방법이다.