Table of contents
프로그램의 핵심은 인풋에 기반하여 결정을 내리는 것이다. 자바스크립트 프로그램도 다를 바 없다. 다만, 값을 쉽게 검사할 수 있다는 사실을 감안할 때, 프로그램적 결정은 인풋 타입에 기반하여 결정된다. 컨디셔널 타입(conditional types)은 타입의 인풋과 아웃풋 사이의 관계에 대해 표현할 때 도움을 준다.
-conditional-type-basic.ts-
interface Animal {
live(): void;
}
interface Dog extends Animal {
woof(): void;
}
type Example1 = Dog **extends Animal ? number : string;**
type Example2 = RegExp **extends Animal ? number : string;**
컨디셔널 타입은 (conditional ? trueExpression : falseExpression)
과 같은 형태로, 자바스크립트의 조건 표현식(conditional expression)과 닮아있다.
SomeType extends OtherType ? TrueType : FalseType;
extends
왼쪽에 있는 타입이 오른쪽에 있는 타입에 등록가능할 때, 우리는 첫번째 브랜치에 있는 타입(TrueType
)을 반환받을 것이며, 반대의 경우에는 뒤의 브랜치에 있는 타입(FalseType
)을 반환받을 것이다.
위 예제에서만 보면 컨디셔널 타입은 그다지 유용해보이지 않는다.
어차피 우리는 Dog
가 Animal
을 확장하고 있다는 사실을 아는 것이 어렵지 않다.
하지만 컨디셔널 타입을 제네릭과 함께 사용한다면 그 진가를 알 수 있다.
예를 들어, 아래와 같은 createLabel 함수를 만든다고 해보자.
interface IdLabel {
id: number;
// ...
}
interface NameLabel {
name: string;
// ...
}
function createLabel(id: number): IdLabel;
function createLabel(name: string): NameLabel;
function createLabel(nameOrId: string | number): IdLabel | NameLabel;
function createLabel(nameOrId: string | number): IdLabel | NameLabel {
throw 'unimplemented';
}
이 createLabel을 위한 오버로드는 인풋의 타입에 기반하여 선택하는 단일 자바스크립트 함수를 표현한다. 다음과 같은 사항에 주목해보자:
createLabel
함수가 새로운 타입을 받아야한다면 그에 따라 또다른 오버로드를 추가해줘야 할 것이다.이러한 문제점을 안고 오버로드를 작성하는 대신, 우리는 컨디셔널 타입과 제네릭을 조합하여 다음과 같이 작성할 수 있다.
type NameOrId<T extends number | string> = T extends number ? IdLabel : NameLabel;