[이펙티브 타입스크립트] - 아이템41 ~ 아이템45

Lee Jeong Min·2022년 3월 30일
1

TypeScript

목록 보기
16/18
post-thumbnail

[아이템41] any의 진화를 이해하기

타입스크립트에서 변수의 타입은 일반적으로 변수를 선언할 때 결정이 된다.

그러나 any 타입의 경우 예외인 경우가 존재한다. (암시적 any | any[] 인 경우 타입이 진화함)

// out의 타입이 진화하는 과정
const range = (start: number, limit: number) => {
  const out = []; // 타입이 any
  for (let i = start; i < limit; i++) {
    out.push(i); // out의 타입이 any[]
  }
  return out; // 타입이 number[]
};

조건문의 분기에 따라 타입이 변할 수 있다.

그러나 아래와 같이 명시적으로 any를 선언하면 타입이 그대로 유지된다.

let val: any;
if (Math.random() < 0.5) {
  val = /hello/;
  val; // 타입이 any
} else {
  val = 12;
  val; // 타입이 any
}
val; // 타입이 any

암시적 any의 경우 변수에 어떠한 할당도 하지 않고 사용하려고 하면 암시적 any 오류가 발생하게 된다.

즉 어떤 변수가 암시적 any 상태일때 값을 읽으려고 하면 오류가 발생한다.

타입을 안전하게 지키기 위해서는 암시적 any를 진화시키는 방식보다 명시적 타입 구문을 사용하는 것이 더 좋은 설계이다.

[아이템42] 모르는 타입의 값에는 any 대신 unknown을 사용하기

any

  • 어떠한 타입이든 any 타입에 할당 가능하다.
  • any 타입은 어떠한 타입으로도 할당 가능하다.

이러한 any의 속성은 ‘한 집합은 다른 모든 집합의 부분 집합이면서 동시에 상위집합이 될 수 없는' 타입 시스템과 상충되는 면을 가지고 있다.

unknown

  • 어떠한 타입이든 unknown 타입에 할당 가능하다.
  • unknown은 오직 unknownany에만 할당이 가능하다.

두 번째 속성으로 이 타입을 사용하려면 적절한 타입으로 변환해야한다.

unknown 타입 변환 방법

  • 타입 단언
  • instanceof 를 체크한 후 unknown에서 원하는 타입으로 변환
  • 사용자 정의 타입 가드로 변환

아래의 예제와 같이 제네릭을 사용하여 변환하는 경우도 있는데, 일반적으로 타입 단언문과 기능이 비슷하며 타입스크립트에서 좋지 않은 스타일이다. 따라서 unknown을 반환하고 사용자가 직접 단언문을 사용하거나 원하는 대로 타입을 좁히도록 강제하는 것이 좋다!

// 제네릭을 사용한것인데, unknown 반환하는것이 더 좋다고함
const safeParseYAML = <T>(yaml: string): T => {
  return safeParseYAML(yaml);
};

unknown과 유사하게 {}, object 타입들이 있다. 그러나 이 타입의 경우 아래와 같은 특성을 가지낟.

  • {} 타입은 nullundefined를 제외한 모든 값을 포함한다.
  • object 타입은 모든 비기본형 타입으로 이루어진다. 객체와 배열이 포함된다.

타입을 잘 알지 못한경우 unknown 사용하자! 라는게 이 장의 주제

[아이템43] 몽키 패치보다는 안전한 타입을 사용하기

자바스크립트는 windowdocument에 값을 할당하여 전역 변수를 만들 수 있다. 그러나 이는 전역 변수가 되기 때문에, 서로 멀리 떨어진 부분들간 의존성을 높이고 사이드 이펙트를 고려해야한다.

또한 타입스크립트에서는 임의로 추가한 속성에 대해서 알지 못한다.

이를 해결하기 위해 아래의 방법이 있다.

  • any 단언문 사용
(document as any).monkey = 'Tarmarin';
  • document, DOM으로부터 데이터를 분리한다.
    • interface의 보강(augmentation)을 사용
      - any보다 타입이 더 안전하다.
      - 속성에 주석을 붙일 수 있다.
      - 속성 자동완성 사용 가능
      - 몽키 패치가 어떤 부분에 적용되었는지 정확한 기록에 남는다.

      그러나 보강은 전역적으로 사용되면 코드의 다른 부분이나 라이브러리로부터 분리할 수 없다. 또한 실행되는 동안 속성 할당시, 실행 시점에 보강 적용방법 X

    • 더 구체적인 타입 단언문 사용(document를 확장한 타입을 만들어 단언문으로 사용)

→ 그러나 몽키 패치를 남용해서는 안 되며, 더 궁극적으로 설계가 잘된 구조로 리팩터링하는 것이 좋다!

[아이템44] 타입 커버리지를 추적하여 타입 안전성 공유하기

noImplicitAny가 설정되어 있어도, any 타입이 여전히 프로그램내에 존재할 수 있는 두 가지 경우

  • 명시적 any타입
  • 서드파티 타입선언

npm의 type-coverage 라는 패키지를 활용하여 any를 추적할 수 있다.

이를 통해 any의 사용을 줄여나가 타입 안전성을 꾸준히 높일 수 있다.

6장 타입 선언과 @types

[아이템45] devDependencies에 typescript와 @types 추가하기

  • dependencies: 프로젝트 런타임시 실행되어야할것들 여기에 포함
  • devDependencies: 런타임에 필요 없는 라이브러리들 포함
  • peerDependencies: 의존성을 직접 관리하지 않는 라이브러리들

ts와 관련 라이브러리들은 일반적으로 devDependencies에 속한다.

TS프로젝트에서 공통적으로 고려해야할 의존성 두 가지

  • 자체 의존성
    • 팀원들 모두가 항상 동일한 버전 사용한다는 보장X

    • 프로젝트 셋업시 별도의 단계 추가

      이 둘의 이유로 시스템 레벨 보단 devDependencies에 넣는 것이 좋다!

  • 타입 의존성
    • @types 의존성은 devDependencies에 있어야 한다.(그러나 항상 유효한 것은 아니고 이와 관련한 몇 가지 문제점이 있다.)
    • 런타임에 @types가 필요한 경우라면 별도의 작업이 필요하다.
profile
It is possible for ordinary people to choose to be extraordinary.

0개의 댓글