Utility Types
포스트
취소

Utility Types

해당 포스트는 typescript util의 사용법에 부족함을 느껴서 필요한 내용을 정리한 포스트입니다.




🌈 Utility Types

utility types로 알아보기

유틸리티 타입은 이미 정의해 놓은 타입을 변환할 때 사용하기 좋은 문법

유틸리티 타입을 꼭 쓰지 않더라도 기존의 인터페이스, 제네릭 등의 기본 문법으로 타입을 변환할 수 있지만 유틸리티 타입을 쓰면 훨씬 더 간결한 문법으로 타입을 정의할 수 있다.

링크

1
2
3
4
5
6
7
8
9
10
11
interface Profile{
  name : string,
  age : number,
  married : boolean
}

const leekboy : Profile = {
  namber: 'leekoby',
  age : 33,
  married: false
}


🍳 Partial

특정 타입의 부분 집합을 만족하는 타입을 정의

1
2
3
4
const newKoby = Partial<Profile>{
  name : 'leekoby',
  age : 33
}

Partial 은 일부분만 필요할 때 필요한 부분만을 쓸 수 있도록 하는 것

🔻 Partial

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


🍳 Pick

1
2
3
4
const newKoby = Pick<Profile, 'name' | 'age'> = {
  name : 'leekoby',
  age : 33
}

위의 Partial 과 같은 동작을 한다.

Profile에서 name과 age를 선택한다. 는 의미

🔻 Pick

1
2
3
type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};


🍳 Exclude

1
type A = Exclude<keyof Profile, 'married'>
type A는 ‘name’‘age’가 된다.

키 중에서 제외하고 싶은 키를 선택할 수 있다.

1
2
3
type Animal = 'Cat' | 'Dog' | 'Human'
type Animal2 = Exclude<Animal, 'Human'>
// Animal2 = 'Cat' | 'Dog'
1
type Exclude<T, U> = T extends U ? never : T;


🍳 Extract

ExtractExclude의 반대

Pick 이랑 유사한 느낌

1
2
3
type Animal = 'Cat' | 'Dog' | 'Human'
type Human = Extract<Animal, 'Human'>
// Human = 'Human'
1
type Extract<T, U> = T extends U ? T : never;


🍳 Omit

위에 작성한 Pick을 다음과 같이 수정할 수 있다.

1
2
3
4
const newKoby : Pick<Profile, Exclude<keyof Profile, 'married'>> = {
 name : 'leekoby',
  age : 33
}

Omit으로 수정해보면

1
2
3
4
const newKoby = Omit<Profile, 'married'> = {
  name : 'leekoby',
  age : 33
}

결과는 같으나 방식은 다르다. Profile에서 married를 제외한 결과를 나타낸다.

많은 속성 중에서 일부만 제외하고 필요할 때 매우 유용하다.

1
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;


🍳 Required

1
2
3
4
5
6
7
8
9
10
11
interface Profile {
  name?: string,
  age?: number,
  married?:boolean
}

const koby : Required<Profile>{
  name : 'koby',
  // age : 33, ❌ age 속성이 필수 입니다.
  married: false
}

옵셔널을 필수 속성으로 만들 수 있다.

1
2
3
type Required<T> = {
    [P in keyof T]-?: T[P];
};

-? 옵셔널을 제거해줌


🍳 Readonly

1
2
3
4
5
6
7
8
9
10
11
12
13
interface Profile {
  name?: string,
  age?: number,
  married?:boolean
}

const koby : Readonly<Profile>{
  name : 'koby',
  age : 33, 
  married: false
}

 koby.name = 'leekoby' // 에러 읽기 전용값으로 수정할 수 없음

수정할 수 없고 값만 가져다 쓸 수 있게 만듦

1
2
3
type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};


🍳 Record

객체를 표현하는 한가지 방법

1
2
3
4
5
6
7
interface Obj {
  [key:string] : number;
}

const a: Obj = { a:3, b:5, c:7}

const b: Record<string, number> = { a:3, b:5, c:7}
1
2
3
type Record<K extends keyof any, T> = {
    [P in K]: T;
};


🍳 NonNullable

1
2
3
type A = string | number | null | undefined | boolean

type B = NonNullable<A>

null과 undefined를 제외함

1
type NonNullable<T> = T extends null | undefined ? never : T;


🍳 Parameters

1
2
3
4
5
6
7
8
9
10
function zip (x: number, y: string, z: boolean): {x: number, y: string, z :boolean} {
  return {x, y, z}
}

type Params = Parameters<typeof zip> // type Params = [x: number, y: string, z: boolean]

type First = Params[0] //number
type Second = Params[1] //string
type Third = Params[2] //boolean

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

함수에 대한 제한을 둘때 아래와 같이 한다.

1
(...args: any) => any

infer는 타입스크립트가 추론하도록 하는 것인고, extends에서만 사용할 수 있다.

추론 조건 ? 초론 성공 시의 값 : 추론 실패시의 값


🍳 ReturnType

위 코드에서 리턴 타입을 추론하도록 수정하려면

1
2
3
type R<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : never;

type Ret = R<typeof zip> // Ret = {x: number, y: string, z :boolean}
1
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;


🍳 ConstructorParameters

abstract new (…args: any) => any

생성자 제한 형태

1
2
3
4
5
6
7
8
9
10
11
12
13
14
class A {
  a: string;
  b: number;
  c: boolean;
  constructor(a : string, b : number, c : boolean){
    this.a = a;
    this.b = b;
    this.c = c;
  }
}

const c = new A('123',456,true)
type C = ConstructorParameters<typeof A> //typeof 클래스가 생성자
// type C = [a : string, b : number, c : boolean]
1
type ConstructorParameters<T extends abstract new (...args: any) => any> = T extends abstract new (...args: infer P) => any ? P : never;


🍳 InstanceType

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class A {
  a: string;
  b: number;
  c: boolean;
  constructor(a : string, b : number, c : boolean){
    this.a = a;
    this.b = b;
    this.c = c;
  }
}

const c = new A('123',456,true)
type I = InstanceType<typeof A>
//type I = A

const a : A = new A('123',456,true) //  인스턴스(new)
1
type InstanceType<T extends abstract new (...args: any) => any> = T extends abstract new (...args: any) => infer R ? R : any;


🍳 기타

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
 * Convert string literal type to uppercase
 */
type Uppercase<S extends string> = intrinsic;

/**
 * Convert string literal type to lowercase
 */
type Lowercase<S extends string> = intrinsic;

/**
 * Convert first character of string literal type to uppercase
 */
type Capitalize<S extends string> = intrinsic;

/**
 * Convert first character of string literal type to lowercase
 */
type Uncapitalize<S extends string> = intrinsic;

function applyStringMapping(symbol: Symbol, str: string) {
    switch (intrinsicTypeKinds.get(symbol.escapedName as string)) {
        case IntrinsicTypeKind.Uppercase: return str.toUpperCase();
        case IntrinsicTypeKind.Lowercase: return str.toLowerCase();
        case IntrinsicTypeKind.Capitalize: return str.charAt(0).toUpperCase() + str.slice(1);
        case IntrinsicTypeKind.Uncapitalize: return str.charAt(0).toLowerCase() + str.slice(1);
    }
    return str;
}

/**
 * Marker for contextual 'this' type
 */
interface ThisType<T> { }




📚 레퍼런스

[리뉴얼] 타입스크립트 올인원 : Part1. 기본 문법편

[리뉴얼] 타입스크립트 올인원 : Part1. 기본 문법편 강의교안

실전 프로젝트로 배우는 타입스크립트

이 기사는 저작권자의 CC BY 4.0 라이센스를 따릅니다.