삼항 연사자처럼 타입도 조건에 따라 타입이 달라지게 프로그래밍 할 수는 없을까?
Condition Type
타입도 삼항 연산자와 유사한 방식으로 조건부 타입을 타입핑할 수 있다.
T extends U ? X : Y
이것을 간단히 리뷰해 보자면, "T가 U에 할당될 수 있는지를 확인하고 이것이 참이라면 X 타입을 사용하고 그렇지 않다면 Y 타입을 사용해라"라는 의미다. 예제를 통해 확인하면 이해가 될 것이다.
interface IItem {
id: number;
}
function getItems<T>(id?: T): T extends number ? IItem : IItem[] {
if (typeof id === "number") {
return { id: 1 } as any;
}
return [{ id: 1 }, { id: 2 }] as any;
}
const result1 = getItems(1); // Type is IItem
const result2 = getItems(); // // Type is IItem[]
- 왜 any를 사용했지?
위 코드를 보면 any를 사용했는데, 이유는 타입스크립트가 타입 유추를 하지 않도록 타입 단언(type assertion) as와 any를 사용했다. 왜냐하면 id 타입이 조건부 타입으로 선택되는 것이 아니므로 함수가 조건문을 평가할 수 없고 Item 타입으로 타입을 좁힐 수 없기 때문이다.
Infer
infer 키워드를 조건부 타입에서 사용하면 실제 분기의 비교할 유형에서 추론하는 방법을 제공해 줄 수 있다.
type GetReturnType<T> = T extends (...args: never[]) => infer R ? R : never;
type Num = GetReturnType<() => number>; // type is number
type Str = GetReturnType<(x: string) => string>; // type is string
type Bools = GetReturnType<(a: boolean, b: boolean) => boolean[]>; // type is boolean[]
조금 더 예제를 확장해 보면 아래와 같이 작성할 수 있다.
type ReturnPromise<T> = T extends (...args: infer A) => infer R ? (...args: A) => Promise<R> : T;
type Promisify<T> = {
[P in keyof T]: ReturnPromise<T[P]> // ref: Mapped Types
}
interface IItemService {
id: string;
getItem(): string;
getItems(): string[];
}
class ItemService implements Promisify<IItemService> {
id: string = '';
getItem() { // type is Promise<string>
return Promise.resolve('')
}
getItems() { // type is Promise<string[]>
return Promise.resolve([''])
}
}
type ReturnPromise = T extends (...args: infer A) => infer R ? (...args: A) => Promise : T;
마지막으로 위 코드만 풀어서 해석하자면 다음과 같다.
- ReturnPromise 타입은 제네릭 타입이며,
- A 타입으로 추론되는 여러 개의 파라미터를 가지며, 리턴 타입이 R로 추론되는 함수 (...args: infer A) => infer R 에
- T 타입이 할당될 수 있다면
- (참일 경우, 타입이 추론 되었기 때문에 타입을 확정할 수 있다) (...args: A) => Promise<R>의 타입을 가지며
- 그렇지 않을 경우 T 타입을 갖는다. (위의 코드에서 id가 프로미스로 랩핑되지 않고 그대로 string 타입을 갖는 이유이다)
깃북으로 보기
https://ajdkfl6445.gitbook.io/study/typescript/condition-type-+-infer#condition-type
반응형
'Typescript' 카테고리의 다른 글
싱글톤 (Singleton Pattern) (0) | 2021.09.19 |
---|---|
[Typescript] 타입 가드(type guard) (0) | 2021.09.18 |
타입스크립트를 도입하며, (0) | 2021.08.07 |
enum 대신 object를 generic을 이용하여 union type으로 변경하기 (1) | 2021.03.20 |
더 나은 타입스크립트 작성하기 3 - readonly (1) | 2020.01.01 |