TypeScript - Utility Type

Evan Lee ㅣ 2022. 9. 15. 16:30

Partial<T>

 

T 타입안에 요소들에 대해서 전부 Optional(?:)로 만들어 준다. 

interface Myinfo {
    name: string,
    age: number,
    phone: number,
    married: boolean,    
}

const jeongmin : Myinfo ={
    name: "jeongmin",
    age: 26,
    phone: 12345678,
    married: false,    
}

const newJeongmin : Partial<Myinfo> ={
    name: "jeongmin",
    age: 26,
}

Partial을 뜯어서 구현을 해자보자면 P<T>으로 지정해줬을 때,

key값은 해당 T 타입의 키값들을 가져와 in 으로 돌려서 순회해서 뽑아내고 [ Key in keyof T

value값은 T타입에 인덱싱을 해서 가져온다. T[Key]

interface Myinfo {
    name: string,
    age: number,
    phone: number,
    married: boolean,    
}

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

const newJeongmin : P<Myinfo> ={
    name: "evan"
}

하지만 아무것도 모든 요소를 Optional로  만들어버리면 아무것도 안넣어도 에러를 발생시키지 않기때문에 선호되지 않는다.  그래서 Pick, Omit을 쓰게 되는데, 쉽게말하면 whitelist랑 blacklist같은거라고 할 수 있다.


Pick<T>,  Omit<T>

interface Myinfo {
    name: string,
    age: number,
    phone: number,
    married: boolean,    
}

const newJeongmin : Pick<Myinfo, 'name'> ={
    name: "jeongmin",
}

const newJeongmin2 : Omit<Myinfo, 'name'> ={
    age: 26,
    phone: 34568945,
    married: false,    
}

Pick을 뜯어서 구현해보자면 

일단 타입을 P<T, S>로 해주는데 S가 무조건 T안에 들어있어야하는 key값이기 때문에 조건을 걸어줘야한다. 그러면 P<T, S extends keyof T> 로 쓸수 있고, key값은 S가 자체가 key값이기때문에 S만 순회해주면된다. 그래서 [Key in S]이고, value값은 T에서 Key값을 인덱싱을 해주어서 구해주면 되기때문에 최종적으로는 밑에처럼 구현 할 수 있다. 

type P<T, S extends keyof T> = {
    [Key in S]: T[Key]
}

const newJeongmin3 : P<Myinfo, 'name'> ={
    name: "jeongmin",
}

 

Omit을 뜯어서 구현해보자 

일단 Omit을 해보기 앞서, Exclude<T, S>를 알아야하는데,

type A = Exclude<keyof Myinfo, 'name'>
// type A = 'age' | 'phone' | 'married'

//lib.es5.d.ts
type Exclude<T, U> = T extends U ? never : T;

Exclude는 S가 key값이라면 T에 keyof를 붙여서 key들중에서 S만뺀 key값들을 반환한다. 그 key값들을 Pick으로 가져오면 그게 Omit타입이된다. 하지만 마지막으로 S또한 T안에 있어야하는 놈이기에 extends keyof T로 방어해준다.

type O<T, S extends keyof T> = Pick<T, Exclude<keyof T, S>>

const newJeongmin3: O<Myinfo, 'name'> = {
    age: 26,
    phone: 3456783,
    married: false,    
}

Required<T>

Require 타입은 간단히, optional이든 뭐든 상관없이 모든 속성들을 Require로 바꿔준다. 사용하기엔 쉬운데 분해해보면 새로운 개념이 나온다고 한다. 위에서 Partial<T>를 보면 모든 속성을 순회하면서 optional로 바꿔주는데, 이것은 그 방식을 차용하지만 수정자를 써서 '-?' 를 넣어서 optional을 무조건적으로 지워준다.  

type R<T> = {
    [Key in keyof T]-?: T[Key];
}

Record<K, T>

Record 타입은 타입의 프로퍼티들을 다른 타입에 매핑시키는 데 사용하는데, 예를 들면 간단히 객체가 하나 있다고 한다면, 

K가 key값의 타입이 되겠고, T는 value값의 타입이 될것이다. 근데 K안에 있는 타입이여야하기 때문에 extends keyof any 넣어준다.

type R<K extends keyof any, T> ={
    [Key in K]: T;
}

const Obj: R<string, number> = {a:3, b:5, c:7}

NonNullable<T>

NonNullable타입은 T에서 null  undefined를 제외한 타입을 만들어줍니다. 

type A = string | null | undefined | boolean

type NoFalsy = NonNullable<A>

// type NoFalsy = string | boolean

Parameters<T>

함수 타입 T의 매개변수 타입들의 튜플 타입을 구성합니다.

function zip(x: number, y: string, z: boolean): { x: number, y: string, z: boolean}{
    return {x,y,z};
}

type P<T extends (...arg: any) => any> = T extends (...args: infer A) => any ? A : never;

type Param = P<typeof zip>;
// type Param = [x: number, y: string, z: boolean];

ReturnType<T>

함수 T의 반환 타입으로 구성된 타입을 만듭니다.

function zip(x: number, y: string, z: boolean): { x: number, y: string, z: boolean}{
    return {x,y,z};
}

type R<T extends (...arg: any) => any> = T extends (...args: any) => infer A ? A : never;

type Ret = R<typeof zip>;
// type Ret = { x: number; y: string; z: boolean; }