해당 포스트는 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'>
|
키 중에서 제외하고 싶은 키를 선택할 수 있다.
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
는 Exclude
의 반대
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;
|
함수에 대한 제한을 둘때 아래와 같이 한다.
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. 기본 문법편 강의교안
실전 프로젝트로 배우는 타입스크립트