[2장] 타입스크립트의 타입 시스템 (1 / 2)
이펙티브 타입스크립트 2장의 아이템 1 - 11을 정리한 내용입니다.
작성일 2024.02.14
페이지가 생성된 시간 2024.10.01 21:01:08

0

2장의 핵심

  • 타입시스템의 기초
  • 타입시스템이 뭔지, 어떻게 사용하는지, 가급적 사용하지 말아야 할 기능은 뭔지
  • 이 책의 나머지를 읽을 때 필요한 개념의 토대이다

아이템6 편집기를 사용하여 타입시스템 탐색하기

  • 타입스크립트는 알아서 타입 추론을 함.. 편집기의 언어서비스를 통해 확인이 가능
  • 타입 선언 파일을 찾아보면 라이브러리가 어떻게 모델링 되었는지, 어떻게 오류를 찾아낼지 살펴볼 수 있다.
// Request를 생성할 때 사용할 수 있는 옵션
interface RequestInit {
  body?: BodyInit | null;
  cache?: RequestCache;
  credentials?: RequestCredentials;
  headers?: HeadersInit;
  // ...
}

아이템7 타입이 값들의 집합이라고 생각하기

  • 타입은 '할당가능한 값들의 집합'
  • 타입체커의 역할은 하나의 집합이 다른 집합의 부분집합인지를 검사하는 것
  • extends의 의미: '~의 부분집합'
  • 타입스크립트 타입이 되지 못하는 값의 집합이 존재한다.
    • ex: 정수에 대한 타입, x, y만을 속성으로 가지는 객체 등
// 속성(프로퍼티)들의 집합이 아니라 타입이 될 수 있는 값의 집합임을 이해하기
interface Person {
  name: string;
}
interface Lifespan {
  birth: Date;
  death?: Date;
}
type PersonSpan = Person & Lifespan;
type K = keyof (Person | Lifespan); // Type is never
// extends가 제네릭 타입에서 한정자로 쓰인다
function getKey<K extends string>(val: any, key: K) {
  // ...
}
getKey({}, 'x'); // OK, 'x' extends string
getKey({}, Math.random() < 0.5 ? 'a' : 'b'); // OK, 'a'|'b' extends string
getKey({}, document.title); // OK, string extends string
getKey({}, 12);
// ~~ Type '12' is not assignable to parameter of type 'string'
// 타입이 되지 못하는 값의 집합 예시
type T = Exclude<string | Date, string | number>; // Type is Date
type NonZeroNums = Exclude<number, 0>; // Type is still just number

아이템8 타입공간의 심벌인지 값공간의 심벌인지 구분 잘 하기

  • 자바스크립트로 변환된 코드를 보면 어떤 공간인지 알 수 있다.
  • 일반적으로 type, interface 뒤는 타입심벌, let, const 뒤는 값심벌
  • class, enum은 타입과 값 두 가지 모두 가능
  • typeof 연산자는 타입공간에서는 타입스크립트 타입을 반환하지만, 값공간(자바스크입트 런타임)에서는 자바스크립트의 타입(문자열로 된)을 반환한다.
  • 클래스 자체의 타입은 typeof 붙여야됨.. 디폴트는 인스턴스의 타입이다. InstanceType을 통해 클래스 타입 -> 인스턴스 타입으로 전환 가능
  • 타입 공간에서 속성접근자는 . 말고 [] 사용해라
  • as const 는 타입추론이 바뀐다.
type User = {
  name: string;
  age: number;
};

const user: User = {
  name: 'jinwook',
  age: 20,
};

type User = {
  readonly name: 'jinwook';
  readonly age: 20;
};

const user: User = {
  name: 'jinwook',
  age: 20,
} as const;

다형성 this 타입 (Polymorphic this types)

다형성 this 타입은 포함하는 클래스나 인터페이스의 하위 타입을 나타냅니다. F-bounded polymorphism이라고 부릅니다. 예를 들어, 계층적으로 유연한 인터페이스를 표현하기 더 쉽게 만듭니다. 각 연산 후에 this를 반환하는 간단한 계산기를 보겠습니다

class BasicCalculator {
  public constructor(protected value: number = 0) {}
  public currentValue(): number {
    return this.value;
  }
  public add(operand: number): this {
    this.value += operand;
    return this;
  }
  public multiply(operand: number): this {
    this.value *= operand;
    return this;
  }
  // ... 다른 연산들은 여기에 작성 ...
}

let v = new BasicCalculator(2).multiply(5).add(1).currentValue();

클래스가 this 타입을 사용하기 때문에, 이를 extend 할 수 있고 새로운 클래스가 아무 변경 없이 이전 메서드를 사용할 수 있습니다.

class ScientificCalculator extends BasicCalculator {
  public constructor(value = 0) {
    super(value);
  }
  public sin() {
    this.value = Math.sin(this.value);
    return this;
  }
  // ... 다른 연산들은 여기에 작성 ...
}

let v = new ScientificCalculator(2).multiply(5).sin().add(1).currentValue();

this 타입 없이, ScientificCalculator는 BasicCalculator를 extend 할 수 없을 것이고 유연한 인터페이스를 유지하지 못할 것입니다. multiply는 sin 메서드를 가지지 않는 BasicCalculator를 반환합니다. 하지만, this 타입으로, multiply는 this를 반환하고, 여기서는 ScientificCalculator을 말합니다.

아이템9 타입단언 보다는 타입선언을

  • 타입단언을 쓰지 말고 타입선언으로 되는지 꼭 먼저 해보자
  • 체이닝이 연속되는 곳이 있다면 체이닝 시작부터 명명된 타입을 가져야 함. 그래야 오류가 정확한 곳에 표시됨
  • DOM엘리먼트 접근 등은 타입스크립트는 모르고 나만 아는 정보로 인해(실제 DOM의 생김새) 타입단언이 필요할 때가 있음
    • 분명히 DOM에는 엘리먼트가 존재하는데 타입스크립트는 undefined 일 수도 있다고 한다.
    • 접미사 '!' => nonnull 단언을 통해 알려주자
  • B as A => A가 B의 부분집합인 경우 또는 B가 A의 부분집합인 경우에만 타입단언이 가능하다. (서로의 서브타입일 경우라고 표현)

아이템10 객체 래퍼 타입 입히기

  • 자바스크립트의 객체 래퍼 동작 이해하기
  • 그리고 그걸 타입스크립트의 타입으로 쓰는것 피하기

아이템11 잉여 속성 체크의 한계

  • 할당 가능 검사와 잉여 속성 체크(엄격한 객체 리터럴 체크)는 별도의 과정
    • 임시 변수 사용 시 잉여 속성 체크 건너뜀
  • 타입 단언 시 잉여 속성 체크는 동작하지 않음
  • 약한 타입: 선택적 속성만 가지는 타입
  • 약한 타입에서는 공통된 속성 검사가 들어간다. 임시변수를 사용해도 적용된다
  • 약한 타입에서는 임시 변수로 할당시에도 잉여 속성 체크와 비슷한 체크가 일어나는데 그걸 공통된 속성 체크라고 하는듯함
interface A {
  a?: string;
  b?: string;
}

const a = {};
const b = { c: 'a' };
const c: A = b; // 이런걸 임시변수를 사용한 할당이라고 함..
// ~~ '{ c: string; }' 유형에 'A' 유형과 공통적인 속성이 없습니다.
©2024 dlwl98
github
PostsAbout