타입스크립트의 타입은 '할당 가능한 값들의 '집합'으로 이해하는 것이 좋습니다. (타입의 범위)
가장 작은 타입 집합은 아무 값도 포함하지 못하는 집합인 never입니다. never로 선언된 변수에는 어떠한 값도 할당 불가입니다.
|
그다음으로
|
작은 집합은 한 가지 값만 포함하는 타입입니다. 이들은 타입스크립트에서 유닛(unit) 타입 이라고도 불리는 리터럴(literal)입니다.
|
type A = 'A';
type B = 'B';
type Twelve = 12;
|
복수개의 리터럴 타입을 묶으려면 유니온(union) 타입을 사용합니다. 유니온은 타입연산자 '|'를 이용해서 만듭니다.
집합에서 합집합의 개념으로 이해할 수 있습니다.
|
type A = 'A';
type B = 'B';
type Twelve = 12;
type AB = A | B;
type AB12 = A | B | Twelve;
|
앞서 설명한 타입들은 범위가 유한하므로 우리가 이해하기 쉽습니다.
그러나 우리가 쓰는 대부분의 타입들의 범위는 무한대로 넓은 경우가 많습니다. 따라서 상대적으로 이해하기 어려울 수 있습니다.
타입이 할당 가능한 값들의 집합이라는 개념에서 아래 예제를 보십시오.
|
interface Identified {
id: string;
};
const test = {
id : 'test',
test: 3,
4: 5
}
const test2 : Identified = test; // 정상
|
Identified 타입에는 'id' 속성에 값이 string인 어떠한 객체도 허용 가능합니다. 이 것을 이해한다면 타입이 할당 가능한 값의 집합이라는 것에 좀 더 친근하게 이해할 수 있습니다.
이번에는 '&'이라는 타입 연산자에 대해서 알아보도록 합시다. 우리는 '&' 는 일반적으로 교집합을 의미한다고 이해합니다.
|
interface Person {
name: string;
}
interface LifeSpan {
birth: Date;
death?: Date;
}
type PersonSpan = Person & LifeSpan;
// PersonSpan 의 타입은 아래와 같습니다.
// {
// name : string;
// birth : Date;
// death?: Date;
// }
|
'&' 연산이 '할당 가능한 범위에 대한 교집합'으로 이해한다면 위 예제의 주석에 대한 설명을 좀 더 이해하는데 도움이 됩니다. 그래서 Person과 LifeSpan 속성을 모두 가지는 값은 PersonSpan 타입에 속하게 됩니다.
|
interface Person {
name: string;
}
interface LifeSpan {
birth: Date;
death?: Date;
}
type K = keyof (Person | LifeSpan); // 타입이 never;
type K2 = keyof (Person & LifeSpan);
const k2: K2 = 'name'; // 정상
const k3: K2 = 'birth'; // 정상
const k4: K2 = 'death'; // 정상
|
아래는 인터페이스 간 집합 관계를 설명하는 예제입니다. 상속받은 인터페이스가 타입의 범위 측면에서 상위 집합이 됩니다.
|
interface Vector1D { x: number; }
interface Vector2D extends Vector1D { y: number; }
interface Vector3D extends Vector2D{ z: number; }
//Vector1D는 Vector2D의 부분집합, Vector2D는 Vector3D의 부분집합.
|
extends 키워드는 제네릭 타입에서 한정자로 쓰일 수 있습니다.
|
declare function getKey<K extends string>(val: any, key: K): void;
getKey({}, 'x'); // 정상) 'x' 값은 string의 서브 집합임.
getKey({}, Math.random() < 0.5 ? 'a' : 'b'); // 정상) 'x' | 'b' 는 string의 서브집합.
getKey({}, 12);// 오류 12는 string의 서브집합이 아님.
|
|
interface Point {
x: number;
y: number;
};
declare function sortByKey<K extends keyof T, T>(vals: T[], key: K): T[];
const pts: Point[] = [
{x: 1, y: 2},
{x: 3, y: 4}
]
sortByKey(pts, 'x'); // 정상
sortByKey(pts, 'y'); // 정상
sortByKey(pts, 'z'); // 비정상.
|
타입이 집합이라는 관점은 배열과 튜플의 관계에서도 명확하게 드러납니다.
|
const list = [1, 2] // 타입은 number[]
const tuple: [number, number] = list // 오류
|
'IT' 카테고리의 다른 글
| Effective Typescript - 9 - 타입 단언보다는 타입 선언을 사용하기 (0) | 2022.01.25 |
|---|---|
| Effective Typescript - 8 - 타입 공간과 값 공간의 심벌 구분하기 (0) | 2022.01.24 |
| Effective Typescript - 5 - any 타입 지양하기 (0) | 2022.01.24 |
| Effective Typescript - 4 - 구조적 타이핑에 익숙해 지기 (0) | 2022.01.24 |
| Effective Typescript - 3 - 코드 생성과 타입이 관계없음을 이해하기 (0) | 2022.01.24 |