Archive

Effective Typescript - week 2 (item 09-10)

|

Effective Typescript - week 2 (item 09-10)


해당 포스트는 [이펙티브 타입스크립트](댄 밴더캄 지음, 장원호 옮김, 인사이트, 2021) 책을 읽으며 정리한 내용입니다.

Item09. 타입 단언보다는 타입 선언을 사용하기

변수에 값을 할당하고 타입을 부여하는 방법은 두 가지가 있다

interface Person {
  name: string;
};

const foo: Person = { name: 'foo' }; // 타입 선언
const poo = { name: 'poo' } as Person; // 타입 단언

타입 선언은 해당 값이 인터페이스를 만족하는지 체크하지만, 타입 단언은 강제로 ‘이 타입이다’라고 간주하기 때문에 타입 체크를 무시한다.

const sin: Person = {}; // Error: 'name' 속성이 '{}' 형식에 없지만 'Person' 형식에서 필수입니다.
const cos = {} as Person; // 정상

속성 추가시에도 적용된다. 타입 선언으로 지정한 객체에 속성 추가시, 해당 속성이 interface에 없으면 오류가 나지만, 타입 단언의 경우에는 그냥 지나간다.


화살표 함수를 사용할 때, 타입 추론으 모호할 때가 있다.

interface MyNumber {
  number: string;
};

const num = ['1', '2', '3'].map((number) => ({ number }));
// const num: { number: string }[]

num의 타입이 { number: string }[]이 된다. MyNumber[] 타입을 원한다고 다음과 같이 작성할 수 있다.

const num = ['1', '2', '3'].map((number) => ({ number } as MyNumber));
// const num: MyNumber[]

위에서처럼 반환되는 값이 {} as MyNumber여도 타입 체크는 오류를 뱉지 않는다.

const num: MyNumber[] = ['1', '2', '3'].map((number): MyNumber => ({ number }));

이렇게 (number): MyNumber number의 타입은 없지만 반환되는 타입을 지정한다.

(number: MyNumber)라고 작성하면 number의 타입은 있지만 반환 타입이 없어서 오류가 난다.


타입스크립트는 DOM에 접근할 수 없기 때문에 이런 경우에는 타입 단언이 활용된다.

document.querySelector('.Button').addEventListener('click', (e) => {
  const button = e.currentTarget as HTMLButtonElement;
});


접두사에 붙이는 ! (확정 할당 어선셜)의 경우에도 타입 단언이라고 볼 수 있다. null이 아님이 확실할 때 사용한다. 아니면 일일이 null 타입 체크를 다 넣어야할지도?


Item10. 객체 래퍼 타입 피하기

원시타입 string은 그 안에 메서드를 가지고 있는 것처럼 보이지만, 실제로는 String 객체로 래핑하고 메서드를 호출하고 마지막에 래핑한 객체를 버리는 식이다.

이 객체 래퍼는 자기 자신 외에는 모두 같지 않다.

'hi' === new String('hi'); // false
new String('hi') === new String('hi'); // false

string은 String에 할당 가능하지만 그 반대의 경우는 성립되지 않는다.

따라서, 타입 선언 시에 잘못 타이핑하지 않도록 주의하자는 댄 형님의 조언 👊



참고 자료


이펙티브 타입스크립트 - 댄 밴더캄 지음