iamkanguk.dev

[TypeScript] T extends U ? X : Y 는 정확히 어떤 의미일까? 본문

Language/TypeScript

[TypeScript] T extends U ? X : Y 는 정확히 어떤 의미일까?

iamkanguk 2024. 3. 16. 22:04

최근에 타입 챌린지를 풀면서 T extends A ? B : C와 같은 코드를 많이 작성했던 것 같다. 그런데 막상 개념은 모르고 그냥 이런 느낌이구나~ 라고만 알면서 문제를 풀었던 것 같아서 찝찝했는데 공부를 하던 중 좋은 글을 확인해서 공부한 내용을 블로그에 적어보려고 한다.

 

참고한 블로그 링크는 아래 참고자료에 첨부 할 예정이니 참고하시면 좋을 것 같다!

 

1.  타입은 가능한 값의 집합이다?

타입은 가능한 값의 집합이다라는 말이 있다. 이 포스팅을 쓰기 전에는 이해가 아예 안됐다. 느낌조차도 오지 않았다 ㅠ

 

예를 들어 never 타입은 어떤 값도 할당할 수 없는 타입이다. 그래서 공집합({})이라고 말할 수 있다. 그런데 number 타입정수, 소수를 할당할 수 있는 타입이다.

 

이 예시를 보면 충분히 이해가 가능하리라고 생각한다.

 

2.  집합 개념에서의 extends 의미 + 서브타입과 슈퍼타입

extends 하면 가장 먼저 떠오르는 단어는 상속이다. 하지만 상속이라는 개념에서 벗어나서 extends 에 대해서 알아보자. 예시 코드를 같이 보면서 알아보자.

function getKey<T extends string>(value: any, key: T) {
	console.log(value, key);
}

 

T extends string 은 무슨 의미일까? extend가 상속의 의미라고만 생각하고 있었을 때는 도저히 이해가 안되었다. T가 string의 자식 클래스다! 라고 해석할 수 있겠지만 지금 우리는 이걸 원하는 것이 아니다.

 

집합의 개념으로 넘어가보면 extend는 하위 집합의 개념이다. 즉, 자식 클래스 = 하위 집합이다. A extends B 라고 하면 A는 B의 하위 집합이다. 그래서 다시 해석해보면 T는 string의 하위 집합이라는 것이다. 그래서 T는 string 타입이 가질 수 있는 것들을 가질 수 있다는 점이다.

 

이 때 T는 단순히 문자열 뿐만 아니라 string literal types 또는 unions of string literal types 도 해당된다.

getKey('A', 'B');   // OK
getKey('A', 'B' | 'C');   // OK
getKey<'lee' | 'kim'>('A', 'B')   // NOPE
getKey<'lee' | 'kim'>('A', 'kim')   // OK
getKey<1111>('A', 'B')   // NOPE

 

우리는 A⊂B를 어떻게 해석할 수 있나? "A는 B의 부분집합이다" 라고 해석할 수 있다. 하지만 "A는 B의 서브타입이고, B는 A의 슈퍼타입이다" 라고도 해석할 수 있다. 참고하는 블로그에 따르면 타입스크립트 프로그래밍 책에서는 다음과 같이 표기한다고 한다.

  • A < B: A는 B의 서브타입이다. 그리고 B는 A의 슈퍼타입이다.
  • A <: B: A는 B와 같거나 B의 서브타입이다. 마찬가지로 B는 A와 같거나 A의 슈퍼타입이다.

 

3.  그래서 우리는  어떻게 해석할 수 있나? + 예제

T extends U ? X : Y 와 같은 타입은 조건부 타입이라고도 부른다. 조건부 타입은 타입스크립트 2.8 버전부터 사용할 수 있는 문법이다. 의미는 T <: U 이면 X를 반환하고 그렇지 않으면 Y를 반환한다는 의미이다.

 

그리고 T가 만약 Union 타입이면 분배법칙을 적용할 수 있다고 한다. Type Challenge의 Exclude 문제를 참고해보자. 문제를 보면 타입 T가 "a" | "b" | "c" 이고, U가 "a" 인데 결과값은 a를 제외한 b와 c가 나와야 한다.

 

T는 지금 유니온 타입이어서 분배법칙이 적용된다. 그렇기 때문에 T의 각 타입이 U에 할당될 수 있는지 확인하고 할당이 된다고 하면 never(공집합) 타입을, 그렇지 않으면 T를 반환하면 Exclude가 구현된다.

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

 

 

이렇게 조건부 타입에 대해서 어느정도 알아보았다. 블로그 포스팅을 쓰면서 많이 이해가 된 것 같다. 타입 챌린지 꼭꼭 풀어보면 좋을 것 같다. 하나하나씩 뭔가 가닥구가 잡혀지는 것 같은 느낌이 많이 든다.


참고자료

- https://mugglim.tistory.com/13

 

[TypeScript] "T extends U ? X : Y"에 대한 고찰

TL;DR 타입은 가능한 값의 집합이다. 서브 타입과 슈퍼 타입을 집합의 관계로 설명할 수 있다. 조건부 타입은 분배법칙을 허용한다. 타입은 집합 타입은 가능한 값의 집합이다. 타입은 가능한 값

mugglim.tistory.com

 

- https://velog.io/@feelslikemmmm/TypeScriptConditional-Type

 

[TypeScript]Conditional Type

Conditional Type

velog.io