Pandaman Blog

[Typescript] Mapped Types 본문

Front end/Typescript

[Typescript] Mapped Types

oyg0420 2022. 2. 24. 21:06

Utility 타입에 대한 궁금증에 내부 코드를 보았고, 내부 코드를 보는 순간 아 잘 모르겠다. 라는 생각으로 Mapped types 이란 것을 공부하기로 했다.

Mapped Types

자바스크립트에서 map 메서드는 배열 내의 모든 요소 각각에 대해 순회하며 새로운 배열을 반환한다.

['1', '2', '3'].map(value => Number(value)); // [1, 2, 3]

map 메서드를 통해서 각 문자열을 숫자로 맵핑하여 새로운 배열을 반환했다. 타입스크립트의 mapped type도 위와 마찬가지로 타입을 순회하며 새로운 타입으로 변환하는것을 의미한다.

index signature

인덱스 시그니처는 타입의 속성 이름을 잘 모르지만 값의 타입을 알 경우 사용된다.

링크

type Person = {
 [key: string]: string;
}


const person: Person = {
  job: 'developer',
  name: 'coo',
}

Keyof 연산자

keyof 연산자는 무엇일까? 공식문에서는 객체 타입의 속성을 string, number, 리터럴 유니온 타입으로 만들어 준다.
바로 아래처럼 말이다.

type Person = {
 name: string;
 age: number;
}


type Keys = keyof Person
// type Keys = 'name' | 'age';

예제를 살펴보자.
링크

keyof 연산자를 통해서 타입의 property만 추출했다. keyof 연산자는 mapped type 에서 매우 유용하게 사용될 수 있다.

union type 을 사용한 mapped type

링크

type Person = {
 name: string;
 age: number;
 job: string;
};

type PersonOnlyString  = { [K in keyof Person]: string; };

// type PersonOnlyString = {
//     name: string;
//     age: string;
//     job: string;
// }

대괄호([ ]) 내부에 K in keyof Person로 작성되어 있는데, in 뒤의 타입(keyof Person)은 꼭 유니온 타입이여야 한다. in앞에 K타입은 유니온 타입중 하나이다. 그리고 순회하며(K: string) 새로운 타입을 반환하는 것이다.

as 를 사용한 key remapping

값의 타입을 맵핑하는 방법도 있지만 as 절을 사용해 속성를 Remapping 하는 방법도 존재한다.
링크

type Person = {
 name: string;
 age: number;
 job: string;
};

type HandlerPersonTypes = {
  [K in keyof Person as `handle${Capitalize<K>}`]: () => void;
}

K in keyof Person 이후 as 절을 사용하여 속성을 handle${Capitalize<K>}로 재맵핑 했다. 그리고 각 속성은 () => void 타입을 갖도록 했다. 결론적으로 해당 Mapped type은 아래와 같다.

type HandlerPersonTypes = {
    handleName: () => void;
    handleAge: () => void;
    handleJob: () => void;
}

사실 언제 사용될지는 잘 모르겠지만...너무 신기하면서 재밌다.

Generic을 사용한 Mapped type

또 다른 예제이다. 모든 객체타입에 대해 옵션널 타입으로 변경해주는 타입을 만들고 싶을때가 있다.
링크

type BeforeType = {
    name: string;
    key: string;
    unit: string;
}

type OptionalType = {
    name?: string;
    key?: string;
    unit?: string;
};

 

위의 예제는 객체 타입의 속성을 모두 Optional 하게 변경한것이다. 이것을 Mapped type을 활용해서 변경할 수 있는 방법이 없을까?
우리에겐 제네릭이 있다.

type Optional<T> = { [K in keyof T]?: T[K] };
// 공통으로 사용할 수 있다.

type OptionalType = Optional<BeforeType>;
  1. 제네릭(<T>) 을 통해 타입인자 T를 받는다.
  2. keyof 연산자를 통해 T의 속성으로 이루어진 유니온 타입을 만든다.
  3. in 키워드를 통해 K?: T[K]를 순회하여 각 속성에 대해 옵션널한 새로운 타입을 반환한다.
  4. T[K] 는 객체 타입(T)에서 특정 속성(K)로 접근한것이다. 즉 특정속성의 타입을 말한다.
    예) BeforType['name'], BeforeType['key'], ...

지금까지 여러방법으로 Mapped 타입을 사용해보았는데, 이보다 더 다양한 방법으로 Mapped 타입을 유용하게 사용할 수 있을 것이다.

'Front end > Typescript' 카테고리의 다른 글

[Typescript] Utility Types - 2  (0) 2022.03.27
[Typescript] Conditional Types  (0) 2022.03.13
[Typescript] Utility Types - 1  (0) 2022.02.21
[Typescript] 함수  (0) 2021.12.19
[Typescript] Type Guard  (0) 2021.12.18
Comments