[Effective TypeScript] 5장 42-44 any 다루기

채동기·2023년 3월 22일
0

TypeScript

목록 보기
18/21

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

  • unknown은 any 대신 사용할 수 있는 안전한 타입입니다. 어떠한 값이 있지만 그 타입을 알지 못하는 경우라면 unknown을 사용하면 됩니다.
function parseYAML(yaml: string): any {
  // ...
}
interface Book {
  name: string;
  author: string;
}
const book = parseYAML(`
  name: Jane Eyre
  author: Charlotte Brontë
`);
alert(book.title);  // No error, alerts "undefined" at runtime
book('read');  // No error, throws "TypeError: book is not a
               // function" at runtime

반환을 any로 하게되면, 작성중에는 오류가 발생하지 않고 런타임에서 오류가 발생합니다. 그리고 사용하는 곳마다 오류가 발생하게 됩니다.

interface Book {
  name: string;
  author: string;
}
function safeParseYAML(yaml: string): unknown {
  return parseYAML(yaml);
}
const book = safeParseYAML(`
  name: The Tenant of Wildfell Hall
  author: Anne Brontë
`);
alert(book.title);
   // ~~~~ Object is of type 'unknown'
book("read");
// ~~~~~~~~~~ Object is of type 'unknown'

unknown 타입을 반환하게 하면 오류를 발생시키고 더 안전하게됩니다.

any, unknown, never 특징

any
- 어떠한 타입이든 any 타입에 할당 가능하다.
- any 타입은 어떠한 타입으로도 할당 가능하다.
unknown
- 어떠한 타입이든 unknown 타입에 할당 가능하다.
- unknown 타입은 어떠한 타입으로도 할당 가능하지 않다.
never
- 어떠한 타입이든 never 타입에 할당 가능하지 않다.
- never 타입은 어떠한 타입으로도 할당 가능하다.
  • 사용자가 타입 단언문이나 타입 체크를 사용하도록 강조하려면 unknown을 사용하면 됩니다.
function parseYAML(yaml: string): any {
  // ...
}
interface Book {
  name: string;
  author: string;
}
function safeParseYAML(yaml: string): unknown {
  return parseYAML(yaml);
}
interface Geometry {}
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 is Book
  }
}

위의 코드처럼 타입 가드를 사용하여 unknown에서 원하는 타입으로 변환할 수 있습니다.

function parseYAML(yaml: string): any {
  // ...
}
interface Foo { foo: string }
interface Bar { bar: string }
declare const foo: Foo;
let barAny = foo as any as Bar;
let barUnk = foo as unknown as Bar;

위의 이중 단언문은 기능적으로 동일합니다. 하지만 나중에 두개의 단언문을 분이하는 리팩터링을 한다면 unknown 형태가 더 안전합니다.

  • {}, object, unknown의 차이점을 이해해야합니다.
{}타입은 null과 undefined 를 제외한 모든 값을 포함합니다.
object 타입은 모든 비기본형(non-primitive) 타입으로 이루어집니다. 여기에는 true 또는 12 또는 "foo"가 포함되지 않지만 객체과 배열은 포함됩니다.

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

몽키패치란(Monkey patch)
몽키패치는 원래 소스코드를 변경하지 않고 실행 시 코드 기본 동작을 추가, 변경 또는 억제하는 기술이다. 쉽게 말해 어떤 기능을 위해 이미 있던 코드에 삽입하는 것이다.

  • 전역 변수나 Dom에 데이터를 저장하지 말고, 데이터를 분리하여 사용해야 합니다.
  • 내장 타입에 데이터를 저장해야 하는 경우, 안전한 타입 접근법 중 하나(보강이나 사용자 정의 인터페이스로 단언)를 사용해야 합니다.

interface의 특수 기능 중 하나인 보강을 사용(아이템 13 보강 참조)

export {};
declare global {
  interface Document {
    /** Genus or species of monkey patch */
    monkey: string;
  }
}
document.monkey = 'Tamarin';  // OK

더 구체적인 타입 단언문을 사용

interface MonkeyDocument extends Document {
  /** Genus or species of monkey patch */
  monkey: string;
}

(document as MonkeyDocument).monkey = 'Macaque';
  • 보강의 모듈 영역 문제를 이해해야 합니다.

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

  • noImplicitAny가 설정되어 있어도, 명시적 any 또는 서드파티 타입 선언(@type)을 통해 any 타입은 코드 내에 여전히 존재할 수 있다는 점을 주의해야 합니다.
  • 작성한 프로그램의 타입이 얼마나 잘 선언되었는지 추적해야 합니다. 추적함으로써 any의 사용을 줄여 나갈 수 있고 타입 안전성을 꾸준히 높일 수 있습니다.

출처

<이펙티브 타입스크립트> (댄 밴더캅 지음, 장원호 옮김, 인사이트, 2021)

profile
what doesn't kill you makes you stronger

0개의 댓글