Item 9 타입 단언보다는 타입 선언을 사용하기

Avoid Type Assertions; Use Type Declarations

interface Person { name: string }

const alice: Person = { name: 'Alice' }  // 타입은 Person (타입 선언)
const alice = { name: 'Alice' } as Person  // 타입은 Person (타입 단언)

타입 선언은 할당되는 값이 해당 인터페이스를 만족하는지 검사하므로 오류를 표시해주지만, 타입 단언은 강제로 타입을 지정한 것이라 타입 체커에게 오류를 무시하라고 하는 것이다.

참고로 타입 단언문 중 이런 문법도 있다.

const bob = <Person>{}
  • 타입 단언문의 원래 문법이며, {} as Person과 동일하다. 그러나 <Person>.tsx(TS+React)에서 컴포넌트 태그로 인식되기 때문에 잘 쓰이지 않는다.

화살표 함수의 타입 선언

const people = ['alice', 'bob', 'jan'].map(name => ({ name }))
// Person[]을 원했으나 결과는 { name: string }[]

이럴 땐 런타임에 문제가 발생할 수 있는 타입 단언보다는 화살표 함수 안에서 타입과 함께 변수를 선언하자.

const people = ['alice', 'bob', 'jan'].map(name => ({
  const person: Person = { name }
  return person
}))  // 타입은 Person[]

좀 더 간결하게 줄여보자. 다음 예시는 앞의 버전과 동일한 타입 체크를 수행한다.

const people = ['alice', 'bob', 'jan'].map(
  (name): Person => ({ name })
}))  // 타입은 Person[]

이번엔 최종적으로 원하는 타입도 직접 명시하고, 타입스크립트가 할당문의 유효성을 검사할 수 있도록 하자.

const people: Person[] = ['alice', 'bob', 'jan'].map(
  (name): Person => ({ name })
}))  // 타입은 Person[]

함수 호출 체이닝이 연속되는 곳에서는 체이닝 시작에서부터 명명된 타입을 가져야 한다. 그래야 정확한 오류가 표시된다.

타입 단언이 꼭 필요한 경우

타입 단언은 타입 체커가 추론한 타입보다 우리가 판단하는 타입이 더 정확할 때 의미가 있다.

예를 들어 DOM 엘리먼트에 대해서 타입스크립트보다는 우리가 더 잘 알고 있을 것이다.

document.querySelector('#myButton').addEventListener('click', e => {
  e.currentTarget  // 타입은 EventTarget
  const button = e.currentTarget as HTMLButtonElement
  button           // 타입은 HTMLButtonElement
})

위의 경우는 우리가 타입스크립트가 알지 못하는 정보를 갖고 있기 때문에 타입 단언문을 쓰는 것이 타당하다.

DOM 타입에 대해서는 Item 55에서 더 자세히 다룬다.

!: Non-null 단언 연산자 (Non-null Assertion Operator)

!는 타입 체커에서 null로 추론하지만 그 값이 null이 아니라고 확신할 때 사용할 수 있다. 변수 뒤에 적어주면 된다.

Last updated