TypeScript - Effective TypeScript 2.6 & 2.7

이소라·2022년 8월 12일
0

TypeScript

목록 보기
12/28

2. TypeScript의 타입 시스템

2.6 편집기를 사용하여 타입 시스템 탐색하기

  • 편집기를 통해서 언어 서비스를 사용할 수 있음

    • 언어 서비스 : 코드 자동 완성, 명세(specification) 검사, 검색, 리팩토링 등
  • 심벌 위에 마우스 커서를 대면, TypeScript가 그 타입을 어떻게 판단하고 있는지 확인 가능함

    • 변수, 함수의 타입을 추론할 수 있음
    • 객체 내 타입을 추론할 수 있음
    • 연산자 중간의 메서드 심벌에 마우스 커서를 대면, 연산자 체인 중간의 추론된 제너릭 타입을 추론할 수 있음
  • 편집기의 'Go to Definition' 옵션을 통해서 라이브러리와 라이브러리의 타입 선언을 탐색할 수 있음

    • 이 옵션을 선택하면 TypeScript에 포함되어 있는 DOM 타입 선언이 lib.dom.d.ts로 이동함
// fetch function in lib.dom.d.ts
declare function fetch(
	input: RequestInfo, init?: RequestInit
): Promise<Response>

type RequestInfo = Request | string;

declare var Request: {
  // 타입과 값이 분리되어 모델링되어 있음
  prototype: Request;
  new(input: RequestInfo, init?: RequestInit): Request;
};

interface RequestInit {
  body?: BodyInit | null;
  cache?: RequestCache;
  credentials?: RequestCredentials;
  headers?: HeadersInit;
  // ...
}
  • lib.dom.d.ts에서 더 많은 타입을 탐색하다 보면, 동작이 어떻게 모델링되었는지, 어떻게 오류를 찾아낼지 알 수 있음

2.7 타입을 값들의 집합으로 생각하기

  • 변수에는 다양한 종류의 값을 할당할 수 있음

    • 런타임에 모든 변수는 각자 고유한 값을 가짐
    • 런타임 전 TypeScipt가 오류를 체크할 때, 변수는 타입을 가지고 있음
    • 타입 = '할당할 수 있는 값들의 집합'
      • 예) number 타입 = 모든 숫자값들의 집합
  • never 타입 = 가장 작은 집합 = 아무 값도 포함하지 않는 집합

// Error : '12' 형식은 'never' 형식에 할당할 수 없음
const x : never = 12;
  • literal 타입 = unit 타입 = 한 가지 값만 포함하는 타입
type A = 'A';
type B = 'B';
type Twelve = 12;
  • union 타입 = 2개 혹은 3개의 타입을 묶은 타입
    • 여러 타입들을 묶을 때 |로 이어줌
    • 값 집합들의 합집합
type AB = 'A' | 'B';
type AB12 = 'A' | 'B' | 12;
  • 집합 관점에서, 타입 체커는 하나의 집합이 다른 집합이 부분 집합인지 검사하는 역할을 함

  • & 연산자는 두 타입의 인터섹션(intersection)을 계산함

    • 인터섹션 타입의 값은 각 타입의 모든 속성을 포함하는 것이 일반적인 규칙임
interface Person {
  name: string;
}
interface Lifespan {
  birth: Date;
  death?: Date;
}
type PersonSpan = Person & Lifespan;

const ps: PersonSpan = {
  name: 'S',
  birth: new Date('1999/09/09'),
  death: new Date('2999/09/09')
} // OK
  • 두 인터페이스의 유니온 타입에 속하는 값은 어떠한 키도 없기 때문에 유니온 타입에 대한 keyof는 공집합이 됨
// K : never 타입
type K = keyof (Person | Lifespan);
// P : 'name' | keyof Lifespan
type P = keyof (Person & Lifespan);
  • 타입이 집합이라는 관점에서 extends의 의미는 '~의 부분 집합'이라고 볼 수 있음
interface Person {
  name: string;
}
// PersonSpan 타입의 모든 값은 name, birth 속성을 가져야함
interface PersonSpan extends Person {
  birth: Date;
  death?: Date;
}
  • 집합의 관점에서 보면 상속한다는 의미를 '부분 집합 범위를 가진다'라고 받아들일 수 있음
function getKey<K extends string>(val: any, key: K) {
  // ...
}

getKey({}, 'x'); // Ok, 'x'는 string을 상속
getKey({}, Math.random() < 0.5 ? 'a' : 'b'); // Ok, 'a'|'b'는 string을 상속
getKey({}, document.title); // Ok, string은 string을 상속
getKey({}, 12); // Error
// 12' 형식의 인수는 'string' 형식의 매개변수에 할당할 수 없음
  • 타입들이 엄격한 상속 관계가 아닐 때는 집합 관계로 보는 것이 이해하기 좋음

    • 예) string|number와 string|Date 사이의 인터섹션은 string임(공집합 아님)
  • 배열에 튜플을 할당할 수 있지만, 반대로 튜플에 배열을 할당할 수 없음

const list = [1, 2] // number[] 타입
const tuple: [number, number] = list; // Error
// 'number[]' 타입은 '[number, number]' 타입의 0, 1 속성에 없음
  • 세 숫자를 가진 배열도 튜플에 할당될 수 없음
    • 이유 : 튜플이 {0: number, 1: number, 2: length}로 모델링되어 있으므로
const triple : [number, number, number] = [1, 2, 3];
const double: [number, number] = triple; // Error
// '[number, number, number]' 형식은 '[number, number]' 형식에 할당될 수 없음
// 'length' 속성의 형식이 호환되지 않음
// '3' 형식은 '2' 형식에 할당될 수 없음
TypeScript 용어집합 용어
never공집합
리터럴 타입원소가 1개인 집합
값이 T에 할당 가능값이 T의 원소
T1이 T2에 할당 가능T1이 T2의 부분 집합
T1이 T2를 상속T1이 T2의 부분 집합
T1과 T2의 유니온T1과 T2의 합집합
T1과 T2의 인터섹션T1과 T2의 교집합
unknown전체 집합

0개의 댓글