아직도 써먹기 힘든 TS - 유틸리티 타입 / Partial

Eddy D veloper·2021년 9월 12일
1


TS에는 타입 적용에 편리한 기능을 미리 정의해논 '유틸리티 타입' 이란게 있다.
이걸 잘 쓰면 부분 추출, 부분 제거, 전체 속성 변경 등 손가락을 덜 혹사시키면서 코딩이 가능하다.
잘 써먹을 수 있도록 유틸리티 타입을 공부 및 모사해보자 👊



목차

  1. 유틸리티 타입 종류
  2. Partial<T>
    1. TS 지식
    2. PartialPerson 만들기
    3. PartialPerson에 제네릭 적용하기

1. 유틸리티 타입 종류

타입스크립트에서 만들어 논 타입 변환을 용이하게 도와주는 도구!
유틸리티 타입은 어떤게 있을까?

Partial<T>, Required<T>, ReadOnly<T>, ...

공식문서에서 안내되고 있는 건 총 20개다.
많긴한데 Partial부터 차근차근 분석해보자!

참고: 유틸리티 타입 - 공식문서

2. Partial<T>

타입 T의 모든 속성을 Optional 하게 만드는 타입이다.
그래서 T의 일부는 있고 일부는 없어도 되는 타입을 만든다.

타입스크립트에 이미 정의된 코드를 살펴보자.

type Partial<T> = {
  [P in keyof T]?: T[P];
}

keyof, in, ? 등 알듯말듯한데, 코드는 생각보다 간단하다.
알듯말듯한 구성요소들을 알아보자.

TS 지식


keyof 연산자

오브젝트 타입의 키를 유니온 타입으로 뽑아내는 연산자

참고: 유니온 타입 - 공식문서
참고: keyof 연산자 - 공식문서


[A in B] 문법

자바스크립트의 for in 문법과 유사하게 동작하는 문법
반복문을 이용하여 타입을 선언할 때 사용된다.
유니온 타입인 B의 요소들이 하나씩 A에 반영되며 작업을 반복하여 처리하는 방식이다.

참고: 타입스크립트의 in 동작방식 - 스택오버플로우


T[P] 문법

Indexed Access Type으로 오브젝트내 속성의 타입을 뽑아낼때 쓸 수 있다.
타입 T의 P 속성에게 설정된 타입을 T[P]로 표현한다.

참고: Indexed Access Type - 공식문서


? 키워드

오브젝트의 특정 속성이 있을 수도 있고 없을 수도 있는 경우 Optional 이라고 말하며, ? 키워드로 표현 가능하다.

참고: Optional - 공식문서



각 요소에 대해 간단하게 정리해봤다.
이를 바탕으로 Partial을 한 문장으로 나타내보자.

💡 타입 T의 모든 키를 순회하면서 해당 키의 타입에 Optional을 추가한다.

그리고 이 문장으로부터 Partial<T>를 모사해보자.

우선, 괜히 어렵게 만들 제네릭은 뒤로하고 Person이라는 타입으로 시작한다.
유틸리티 타입 Partial<T>을 사용한 Partial<Person>의 결과와 동일한 PartialPerson 타입을 만들어보자.

PartialPerson 만들기


사용할 타입과 원하는 결과

Person 타입

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

Partial<Person>


진행 과정
1. Person의 키 목록을 가져오고
2. 키 목록을 순회하면서
3. 각 키의 원래 타입을 적용하고
4. Optinal도 또한 적용한다.


1. Person의 키 목록 가져오기

keyof를 사용하여 키 목록을 가져와보자.
아래 사진처럼 키들이 유니온 타입으로 묶여나온다.


2. 키 목록을 순회하기

[A in B]의 동작 방식을 익힐 겸 1번의 결과( PersonKeyOf )를 이용하여 MappedPerson이라는 새로운 타입을 만들어보자.

MappedPerson은 모든 키의 타입이 string을 가진다.

type MappedPerson = {
  [P in PersonKeyOf]: string;
}

keyof + [A in B] 를 이용해서 위처럼 코딩이 가능한데, 결과 사진을 보기전에 어떻게 처리가 될 지 상상해보자.

P가 가지게 되는 값들은 PersonKeyOf('name', 'age', 'height', 'weight') 이다.

이 4가지 값들로 반복문이 돈다고 생각하면,

P가 name 인 경우, name: string;
P가 age 인 경우, age: string;
P가 height 인 경우, height: string;
P가 weight 인 경우, weight: string;

이런 식의 흐름이 되어 위 4가지가 모인 새로운 타입 MappedPerson이 만들어진다.

MappedPerson


3. 각 키의 원래 타입 적용하기

MappedPersonstring이 아닌 원래 타입을 가져오기 위해서 T[P]을 사용하자.
우리 상황에선 T에 해당하는 값은 Person이다.
그렇게 만든 새로운 타입을 IndexedAccessPerson이라 하자.

type IndexedAccessPerson = {
  [P in PersonKeyOf]: Person[P];
}

동장 방식은 당연히 2번과정과 동일하다. 대신 타입이 다르다.

P가 name 인 경우,
name: Person[name];name: string;
P가 age 인 경우,
age: Person[age];age: number;
P가 height 인 경우,
height: Person[height];height: number;
P가 weight 인 경우,
weight: Person[weight];weight: number;

최종적으로 적용된 4가지가 모여서 IndexedAccessPerson이 만들어진다.

IndexedAccessPerson


4. Optinal 적용하기

? 키워드: 앞에 붙여주면 최종 타입 PartialPerson이 만들어진다.

type PartialPerson = {
  [P in PersonKeyOf]?: Person[P]; 
}

과정은 2,3 번을 통해 충분한 연습이 됬다 생각하니 바로 결과 사진을 보자.

PartialPerson


PartialPerson에 제네릭 적용하기

type PartialPersonV1 = {
  [P in PersonKeyOf]?: Person[P]; 
}

// 1. PersonKeyOf -> keyof Person
type PartialPersonV2 = {
  [P in keyof Person]?: Person[P]; 
}

// 2. Person -> Generic
type PartialPerson<T> = {
  [P in keyof T]?: T[P]; 
}

// Original Patrial
type Partial<T> = {
  [P in keyof T]?: T[P];
};

여기까지 기존 타입에 optional 속성을 추가하는 Partial에 대해 공부했다.

바탕이 되는 개념인 keyof, [A in B], Indexed Access Type, Optional에 대해서도 알 수 있었고, Partial 모사를 통해 독립적이였던 개념들을 연결시킬 수 있었다.

공부하면서 작성한 코드입니다.
Optional 모사하기

모르고 있던게 많아 정리하면서 진행하느라 분량이 길어졌네요.
나머지 타입들은 다음 포스팅으로 넘기겠습니다.


공부한 내용을 공유하는 글이니 제가 잘못된 정보를 전달할 수도 있습니다.
그럴 땐 거침없이 태클걸어주세요.


1개의 댓글

comment-user-thumbnail
2022년 5월 5일

오 Partial 정의 부터 파고드는 글이라 그런지 정말 유익했습니다 !

답글 달기