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

Yongwoo Cho·2022년 6월 9일
0

TIL

목록 보기
86/98
post-thumbnail

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

function range(start: number, limit: number) {
  const out = []; // type: any[]
  for (let i = start; i < limit; i++) out.push(i); // type: any[]
  return out; // type: number[]
}

out의 타입은 any[]로 선언되었지만 number 타입의 값을 넣는 순간부터 타입은 number[]로 진화한다. any 타입의 진화는 noImplicitAny가 설정된 상태에서 변수의 타입이 암시적으로 any인 경우에만 일어난다.

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

하지만 명시적으로 any를 선언하면 타입이 그대로 유지된다.

function range(start: number, limit: number) {
  const out = [];
  if (start === limit) return out; // ❌ 'out'변수에는 암시적으로 'any[]'형식이 포함됩니다.
  for (let i = start; i < limit; i++) out.push(i);
  return out;
}

any 타입의 진화는 암시적 any타입에 어떤 값을 할당할 때만 발생한다. 그리고 어떤 변수가 암시적 any 상태일 때 값을 읽으려고 하면 오류가 발생한다.

function range(start: number, limit: number) {
  const out = [];
  range(start, limit).forEach((i) => out.push(i * i));
  return out; // ❌ 'out'변수에는 암시적으로 'any[]' 형식이 포함됩니다.
}

❗ 암시적 any 타입은 함수 호출을 거쳐도 진화하지 않는다.

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

✔️ any 특징

  1. 어떠한 타입이든 any 타입에 할당 가능하다.
  2. any 타입은 어떠한 타입으로도 할당 가능하다.
    ✔️ never 특징
  3. 어떠한 타입도 never에 할당할 수 없다.
  4. any와 동일
    ✔️ unknown 특징
  5. any와 동일
  6. unknown은 오직 unknown과 any에만 할당 가능하다.

❗ unknown 타입인 채로 값을 사용하면 오류가 발생한다.

변수 선언을 할 때 어떠한 값이 있지만 그 타입을 모르는 경우에 unknown을 사용한다.
ex) parseYAML

✔️ unknown에서 원하는 타입으로 변경

  • instanceof
function processValue(val: unknown) {
  if (val instanceof Date) val; // type: Date
}
  • 사용자 정의 타입 가드
function isBook(val: unknown): val is Book {
  return (
    (typeof val === "object") & (val !== null) &&
    "name" in val &&
    "author" in val
  );
}
function processValue(val: unknown) {
  if (isBook(val)) val; // type: Book
}

✔️ object, {} vs unknown

  • {} 타입은 null과 undefined를 제외한 모든 값을 포함
  • object 타입은 모든 비기본형 타입으로 이루어짐.

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

타입 체커는 Document와 HTMLElement의 내장 속성에 대해서는 알고 있지만, 임의로 추가한 속성에 대해서는 알지 못한다.

document.monkey = "Tamarin"; // ❌ 'Document' 유형에 'monkey' 속성이 없습니다.
(document as any).monkey = "Tamarin"; // 정상

✔️ 최선의 해결책 : document 또는 DOM으로부터 데이터를 분리하는 것

분리할 수 없는 경우

  • interface의 특수 기능 중 하나인 보강을 사용하는 것
interface Document {
  monkey: string;
}
document.monkey = "Tamarin";

👍 any보다 나은 점

  • 타입이 더 안전함. 타입 체커는 오타나 잘못된 타칩의 할당을 오류로 표시

  • 속성에 주석을 붙일 수 있음

  • 속성에 자동완성을 사용할 수 있음

  • 더 구체적인 타입 단언문 사용하기

interface MonkeyDocument extends Document {
  monkey: string;
}
(document as MonkeyDocument).monkey = "Macaque";

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

❗noImplicitAny가 설정되어 있어도, 명시적 any 또는 서드파티 타입 선언(@types)을 통해 any 타입은 코드 내에 여전히 존재할 수 있다.

npm의 type-coverage 패키지 활용하여 any추적

$ npx type-coverage
$ npx type-coverage --detail
profile
Frontend 개발자입니다 😎

0개의 댓글