분산적인 조건부 타입

woodstock·2024년 2월 5일
0
post-thumbnail

분산적인 조건부 타입

예제 1.

// 조건부 타입

type StringNumberSwitch<T> = T extends number ? string : number;

let a: StringNumberSwitch<number>;

let b: StringNumberSwitch<string>;

타입 변수에 다음과 같이 Union타입을 할당해 보자.

type StringNumberSwitch<T> = T extends number ? string : number;

(...)

let c: StringNumberSwitch<number | string>;
// string | number

조건부 타입 문법에 따라 number | stringnumber의 서브타입이 아니므로 조건식이 거짓이 되어 변수 c의 타입이 number가 될거라고 예상할 수도 있다.

그러나, 변수 cstring | number 타입으로 정의된다.

그 이유는 조건부 타입의 타입 변수에 Union 타입을 할당하면 분산적인 조건부 타입으로 조건부 타입이 업그레이드 되기 때문이다.

분산적인 조건부 타입은 다음과 같이 동작한다.

타입 변수에 할당한 Union 타입 내부의 모든 타입이 분리된다. 따라서 StringNuberSwitch<number | string> 타입은 다음과 같이 분산된다.

  • StringNumberSwitch<number>
  • StringNumberSwitch<string>

그리고 다음으로 분산된 각 타입의 결과를 모아 다시 Union 타입으로 묶는다.

  • 결과 : number | string

예제 2.

let d: StringNumberSwitch<boolean | number | string>;
// 1단계
// StringNumberSwitch<boolean> |
// StringNumberSwitch<number> |
// StringNumberSwitch<string>

// 2단계
// number |
// string |
// number

// 결과
// number | string

Exclude 조건부 타입 구현하기

분산적인 조건부 타입의 특징을 이용하면 매우 다양한 타입을 정의할 수 있다.

예를 들어, Union 타입으로부터 특정 타입만 제거하는 Exclude(제외하다) 타입을 다음과 같이 정의할 수 있다.

type Exclude<T, U> = T extends U ? never : T;

type A = Exclude<number | string | boolean, string>;

위 코드는 다음의 흐름으로 동작한다.

1. Union 타입이 분린된다.

  • Exclude<number, string>
  • Exclude<string, string>
  • Exclude<boolean, string>

2. 각 분리된 타입을 모두 계산한다.

  • T = number, U = string 일 때 number extends string 은 거짓이므로 결과는 number
  • T = string, U = string 일 때 string extends string 은 참이므로 결과는 never
  • T = boolean, U = string 일 때 boolean extends string 은 거짓이므로 결과는 boolean

3. 계산된 타입들을 모두 Union으로 묶는다

  • 결과 : number | never | boolean


    계산 결과 타입 A는 number | never | boolean 타입으로 정의되는데, 이때 공집합을 의미하는 never 타입은 Union으로 묶일 경우 사라진다. 공집합과 어떤 집합의 합집합은 그냥 원본 집합이 되기 때문이다.

따라서, 최종적으로 타입 Anumber | boolean 타입이 된다.


Extract 조건부 타입 구현하기

type Extract<T, U> = T extends U ? T : never;

type B = Extract<number | string | boolean, string>;


분산적인 조건부 타입 막기

분산적인 조건부 타입이 되지 않도록 막고 싶다면 extends의 양 옆에 대괄호를 씌워주면 된다.

type StringNumberSwitch<T> = [T] extends [number] ? string : number;

let d: StringNumberSwitch<boolean | number | string>;
// 결과 number

boolean | number | string Union 타입은 extends number가 거짓이 되므로 최종적으로 그냥 number가 되는 것이다.

profile
해내는 사람

0개의 댓글