👶 TypeScript

조건부 타입 - 분배적 조건부

개발자 린다씨 2023. 1. 21. 12:00
반응형

분배적 조건부

TypeScript에선 지금까지 살펴본 예에서처럼 간단한 조건을 다양한 방식으로 표현할 수 있습니다.

 

이는 분배 법칙(distributive law)을 따르기 때문입니다.

 

즉 왼쪽의 표현식은 오른쪽의 표현식과 동일합니다.

아래의 표현식은 다음과 같습니다.
string extends T ? A : B string extends T ? A : B
(string | number) extends T ? A : B (string extends T ? A : B) | (number extends T ? A : B)
(string | number | boolean) extends T ? A : B (string extends T ? A : B) | (number extends T ? A : B)
| (boolean extends T ? A : B)

T라는 가변 타입의 인수를 받아 T[]과 같은 배열 타입으로 변환하는 함수가 있다고 가정합시다.

 

이때 T에 유니온 타입을 전달하면 무슨 일이 일어날까요?

type ToArray<T> = T[]
type A = ToArray<number> // type A = number[]
type B = ToArray<number | string> // type B = (string | number)[]

상당히 직관적입니다.

 

그렇다면 조건부 타입을 추가하면 어떻게 될까요? 다음을 살펴보겠습니다.

type ToArray2<T> = T extends unknown ? T[]: T[]
type A = ToArray2<number> // type A = number[]
type B = ToArray2<number | string> // type B = number[] | string[]

조건부 타입을 사용하면 TypeScript는 유니온 타입을 조건부의 절들로 분배합니다.

 

조건부 타입을 가져다가 유니온의 각 요소로 매핑(분배)하는 것과 같은 결과입니다.

 

이를 이용한다면 다양한 공통 연산을 안전하게 표현할 수 있습니다.

 

예를 들어 TypeScript는 두 타입의 공통부분을 구해주는 &와 두 타입의 유니온을 만들어주는 |를 제공합니다.

 

이번엔 T에는 존재하지만 U에는 존재하지 않는 타입을 구하는 Without<T, U>를 구현해 보겠습니다.

type Without<T, U> = T extends U ? never: T

Without은 다음처럼 사용할 수 있습니다.

type Without<T, U> = T extends U ? never: T
type A = Without<boolean | number | string, boolean> // type A = string | number

TypeScript가 이 타입을 어떻게 구해내는지 따져봅시다.

 

1. 입력부터 시작합니다.

type A = Without<boolean | number | string, boolean>

2. 조건을 유니온으로 분배합니다.

type A = Without<boolean, boolean > | Without<number, boolean> | Without<string, boolean>

3. Without의 정의를 교체하고 T와 U를 적용합니다.

type A = (boolean extends boolean ? never : boolean) | (number extends boolean ? never : number) | (string extends boolean ? never : string)

4. 조건을 평가합니다.

type A = never | number | string

5. 단순화합니다.

type A = number | string

조건부 타입에 분배 속성이 없었다면 얻을 수 있는 게 never 뿐이었을 것입니다.

반응형