[이펙티브 타입스크립트] 2장 타입스크립트의 타입 시스템 (9,10,11장)

Urther·2022년 10월 3일
0

아이템 9. 타입 단언보다는 타입 선언을 사용하기

타입스크립트에서 변수에 값을 할당하고 타입을 부여하는 방법은 두 가지이다.

interface Person {name:string}

const alice:Person = {name:'Alice'}; // 타입은 Person
const bob = {name:'Bob'} as Person // 타입은 Person

이 두 가지 방법은 결과가 같아보이지만 그렇지 않다.

const alice:Person = {name:'Alice'}; 방법은 타입 선언을 붙여서 그 값이 선언된 타입임을 명시한다.

const bob = {name:'Bob'} as Person 방법은 타입 단언을 수행한다. 타입스크립트가 추론한 타입이 있음에도 Person 타입으로 간주해버린다.

const bob = { } as Person

name 이라는 key 값이 없어도 강제로 타입을 지정해놨기 때문에 타입 체커에게 오류를 무시하라고 의미 하게 된다. 따라서, 타입 단언 보다는 타입 선언을 사용해야 한다.

화살표 함수의 타입 추론이 모호한 경우

const People=['alice', 'bob', 'jan'].map(name=>{name})

// 내가 원하는 People 의 타입은 Person[] 
// 하지만 타입 추론은 People:{name:string}[] 

이런 문제를 해결하기 위해

const People=['alice', 'bob', 'jan'].map(name=>{name} as Person)

으로 사용하는 것이 아니라, 아래와 같이 선언해준다.

const People=['alice', 'bob', 'jan'].map((name):Person=>{name})

// 이렇게 사용했을 때 People:Person[] 형태가 만들어질 수 있다.

DOM 엘리먼트 접근

타입스크립트는 DOM에 접근할 수 없기 때문에 정확한 타입 추론이 어렵다.

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

우리는 #myButton 이 버튼 엘리먼트인지 알지만, 타입스크립트는 알지 못한다. 그렇기 때문에 currentTarget이 있어야 하는지 인식하지 못한다. (어떻게 선언해주어야하는지는 후반에 더 잘나오게 될 것)

특별한 문법(!)을 통해 null이 아님을 단언 할 수 있다.
보통, 변수에 const H=!true 처럼 사용하게 되면, 부정의 의미로 사용되지만 접미사로 사용하는 경우에는 일반적인 단언문이라고 생각해야한다.

const el=document.getElementById('foo')!;

이럴 경우에는 null이 아니라고 확신할 수 있을 때 사용해야한다. 그렇지 않는다면 조건문을 통해 null을 체크하는 것이 좋다.

결론적으로,
타입스크립트보다 타입에 대한 정보를 잘 알고 있을 때 타입의 단언문을 사용하는 것은 괜찮다.

아이템 10. 객체 래퍼 타입 피하기

자바스크립트는 객체 외에도 기본 형 값들에 대한 일곱자기 타입이 있다.

  1. string
  2. number
  3. boolean
  4. null
  5. undefined
  6. symbol (ES2015 추가)
  7. bigint

기본형은 불변이며, 메서드를 가지지 않는다는 점에서 객체와 구분된다.

'primitive'.charAt(3)

하지만 , 위와 같은 예제는 메서드를 가지고 있는 것처럼 보이게 된다. string 기본형에는 없지만 String 객체 타입에는 메서드를 가지고 있기 때문이다.

자바스크립트의 동작,
string(기본형)=> String(객체)로 매핑=>메서드 호출

그러나, string 타입을 String(객체)로 사용하면 다른 타입이라고 인지하기 때문에 주의해야합니다.

아이템 11. 잉여 속성 체크의 한계 인지하기

타입이 명시된 변수에 객체 리터럴을 할당할 때 타입스크립트는 해당 타입의 속성이 있는지, 그 외의 속성은 없는지 확인합니다.

interface Room{
  numDoors:number;
  ceilingHeightFt:number;
}

const r: Room={
  numDoors:1,
  ceilingHeightFt:10,
  elephant:'present'
  
  // error ! Room 형식에는 알려진 속성만 지정 가능
}

객체 리터럴은 알려진 속성으로만 지정할 수 있다 !!
elephant는 타입 Room에 없는 속성이기 때문에 에러가 발생한다.

이것은 구조적 타이핑 관점에서 안맞는다고 생각할 수 있다.

interface Room{
  numDoors:number;
  ceilingHeightFt:number;
}

const obj={
    numDoors:1,
  ceilingHeightFt:10,
  elephant:'present'
}

const r: Room=obj; //정상

위와 달리 아래는 정상으로 타입 체커를 통과할 수 있다.
이와 같은 동작이 가능한 이유는 잉여 속성 체크 과정이 수행되기 때문이다. (잉여 속성 체크 과정은 객체 리터럴로 선언되지 않은 경우와 단언문으로 작성되어있는 경우 수행되지 않는다)

profile
이전해요 ☘️ https://mei-zy.tistory.com

0개의 댓글