HomeAboutMeBlogGuest
© 2025 Sejin Cha. All rights reserved.
Built with Next.js, deployed on Vercel
👻
개발 기록
/
🐧
이펙티브 타입스크립트
/
📗
5장 any 다루기
📗

5장 any 다루기

  • any를 쓰면 안되는 이유 → 깔끔, 정확, 명료한 코드 작성을 위해 제대로 된 타입 설계는 필수인데 이 타입 설계가 명확해지지 않아 코드를 읽기 힘들어짐.
  • 편집기에서 rename symbol로 타입의 이름을 변경할 수 있다!?
  • 그럼에도 불구하고 any는 점진적 마이그레이션을 위해 존재해야 함.
  • 더 잘 쓰는 방법
    • 좁은 범위에서 any 사용하기
    • interface Foo { foo: string; } interface Bar { bar: string; } declare function expressionReturningFoo(): Foo; function processBar(b: Bar) { /* ... */ } function f1() { const x: any = expressionReturningFoo(); // Don't do this processBar(x); } function f2() { const x = expressionReturningFoo(); processBar(x as any); // Prefer this }
      const config1: Config { a: 1, b: 2, c: { key: value // 에러, Foo 타입에 foo 프로퍼티가 필요하지만 Bar 타입에는 없습니다. } } const config2: Config { a: 1, b: 2, c: { key: value } as any // 정상, a,b 프로퍼티 마저 타입체크 안됨 } const config3: Config { a: 1, b: 2, c: { key: value as any // 정상, a,b 프로퍼티 마저 타입체크 가능 } }
    • 구체적으로 변형해서 사용하기
    • function getLengthBad(array: any) { return array.length; } // better than above. function getLength(array: any[]) { return array.length; } // 배열의 배열 형태 : any[][] // value만 모를 때 function paramTest({[key: string]: any}) { ... } // ㅊㄱ) object 타입은 속성에 접근할 수 없음.
      // 함수의 any type Function0 = () => any; // 매개변수 0개만 가능 type Function1 = (arg: any) => any; // 매개변수 1개만 가능 type Function2 = (...args: any[]) => any; // 매개변수 몇 개든 가능.
 

item 40

  • 타입 단언을 불가피하게 사용해야 한다면, 정확한 정의를 가지는 함수 안으로 숨기자.
function shallowObjectEqual<T extends object>(a: T, b: T): boolean { for (const [k, aVal] of Object.entries(a)) { if (!(k in b) || aVal !== (b as any)[k]) { return false; } } return Object.keys(a).length === Object.keys(b).length; }
 

item 41

  • any는 타입을 진화시킴.
function range(start: number, limit: number) { const out = []; for (let i = start; i < limit; i++) { out.push(i); } return out; // Return type inferred as number[] }
  • 하지만 암시적 any 상태인 변수에 어떤 할당도 하지 않고 사용할 경우 암시적 any 오류가 발생하게 됨.
function makeSquares(start: number, limit: number) { const out = []; // ~~~ Variable 'out' implicitly has type 'any[]' in some locations range(start, limit).forEach(i => { out.push(i * i); }); return out; // ~~~ Variable 'out' implicitly has an 'any[]' type }
  • 따라서 any를 진화시키는 방식보다 명시적 타입 구문을 사용하는 것이 안전한 타입을 유지하는 방법임.
 

item 42

  • any 대신 unknown을 사용하자.
  • unknown에서 원하는 타입으로 변환할 수도 있음.
function processValue(val: unknown) { if (val instanceof Date) { val // Type is Date } } //or 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 } }
  • {} 타입은 null과 undefined를 제외한 모든 값을 포함함.
  • object 타입은 모든 non-primitive 타입으로 이루어짐. ex) 객체, 배열
  • unknown 타입이 도입되기 전에 {}가 일반적으로 사용되었음. 이젠 아님.
 

item 43

  • 몽키 패치보다는 안전한 타입을 사용하자.
    • 몽키 패치 : 런타임 중인 프로그램 메모리의 소스 내용을 직접 바꾸는 것.
  • 내장 타입에 데이터를 저장해야 하는 경우, 보강이나 사용자 정의 인터페이스로 단언하는 방법을 사용하자.
// 보강 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';
 

item 44

  • noImplicitAny를 설정해도 명시적 any 또는 서드파티 타입 선언(@types)을 통해 any 타입은 코드 내 여전히 존재할 수 있음.
  • npm의 type-cover-age 패키지를 활용해 any를 추적할 수 있음.
  • type-coverage 실행 시 —detail 플래그를 붙이면, any 타입이 있는 곳을 모두 출력함.