본문 바로가기

프로그래밍 공부내용/타입스크립트(TS)

타입스크립트 조건부 타입 (Conditional type)

본 글은 이웅재님의 영상(https://www.youtube.com/watch?v=ViS8DLd6o-E) ~1:10:09 을 보고 제 나름대로 기억하기 위해서 정리한 글 입니다.

 

1. type과 interface의 차이?

- 우선은 문법의 차이입니다.

interface a {
  name: string;
}

type b = {
  name: string;
};

보면 interface 는 = 연산자 없이 사용하고 있습니다.

 

- 두번째로는 vscode 내에서 사용할 때의 차이입니다.

interface는 찍어봣을 때 a의 구조가 어떤지 알려주지 않지만, type alias인 b는 어떤 구조를 가지는지 알려줍니다.

인터페이스를 마우스로 찍어봤을 때

 

type을 마우스로 찍어봤을 때

- 세번째는 기능차이입니다. 

interface는 선언병합을 제공하고 type alias는 제공하지 않습니다.

 

- 네번째로 추가사항인데, type과 interface의 역사에 관한 내용입니다.

항상 궁금했던 건데 타입스크립트를 오래하시고 또 잘하시는 분이라 그런지 명쾌하게 대답을 해 주셨습니다.

굳이 왜 나눴을까 생각을 항상 했었습니다.

웅재님이 소개해 주신 차이로는 예전에는 type alias를 사용했을 때에는 실제로 그 type alias가 가지는 이름을 가지지 않고 디버깅이 됐었다고 합니다. 처음 만들 때 type은 상속하거나 하지 않고 그냥 타입에 대한 이름을 임시로 준다는 느낌을 가졌던 것 같고  inteface는 실제 새로운 타입 하나를 만들 때 써라는 느낌으로 개발하지 않았나 싶습니다.

 

 

2. Conditional Type

object에 타입을 달아줄 때

 

'종류'에는 '새', '호랑이' 가 들어갈 수 있고, 

'행동'에는 '날다', '뛰다' 만 들어가게 하고 싶을 때 유용합니다.

 

generic을 이용하면 간단하게 구현할 수 있습니다.

generic은 타입을 일종의 변수처럼 사용할 수 있게 해준다고 생각하면 됩니다.

 

type Animal<T> = {
  id: T;
  activity: T extends "bird" ? "fly" : "run";
};

const myPet: Animal<"bird"> = { id: "bird", activity: "fly" };

 

조금 더 심화해서, id에 새랑 호랑이 밖에 못쓰게 해 봅시다.

 

type Animal<T> = {
  id: T extends "bird" | "tiger" ? T : never;
  activity: T extends "bird" ? "fly" : T extends "tiger" ? "run" : never;
};

const myPet: Animal<"bird"> = { id: "bird", activity: "fly" };

never를 사용하면 가능합니다.

typescript 에서 삼항연산자와 같은 것을 조건부로 사용할 수 있게 해 주는게 정말 기깔납니다.

 

keyof 를 이용해서 간단한 flatten type을 만들어볼 수 도 있습니다.

type Flatten<T> = T extends any[] ? T[number] : T extends object ? T[keyof T] : T;

const numbers = [1, 2, 3];
type NumbersArrayFlatten = Flatten<typeof numbers>; //type = number
// typeof numbers = number[] -> number[] extends any[] -> T[number] = number

const person = { name: "been", age: 28 };
type PersonFlatten = Flatten<typeof person>; //type = string|number
//typeof person = object -> T[keyof T] -> T['id'|'number'] -> T['id'] | T['number'] -> number | string