TypeScript이 제공하는 다양한 유틸리티 타입에 대해 정리하고자 합니다.
내부 로직 크게 어렵지 않기 때문에 자주 쓰이는 유틸들은 직접 구현해보는 것을 추천합니다.
(면접 때 물어봐서 당황했던 기억이 나네요 😅)
💡 용어 정리
- T : 타입
- U : 또 다른 타입
- K : 속성(key)
Partial<T>
T의 모든 프로퍼티를 선택적 프로퍼티로 변경한 새로운 타입을 반환합니다.
구현
type Partial<T> = {
[P in keyof T]?: T[P];
};
keyof T는 T의 모든 키 값을 가지는 유니온 타입을 의미합니다.
인덱스 시그니처 문법이 아직 익숙지 않으면 이 글을 참고하면 좋습니다.
예시
interface User {
name: string;
age: number;
}
interface PartialUser {
name?: string;
age?: number;
}
Required<T>
Partial과 반대로 T의 모든 프로퍼티를 필수 프로퍼티로 변경한 새로운 타입을 반환합니다.
구현
type Required<T> = {
[P in keyof T]-?: T[P];
};
마이너스 기호는 2.8 버전에 추가된 일종의 remove modifiers입니다.
즉 옵셔널 프로퍼티(?
기호)를 제거하는 역할을 합니다.
예시
interface User {
name?: string;
age?: number;
}
interface RequiredUser {
name: string;
age: number;
}
Readonly<T>
T의 모든 프로퍼티를 읽기 전용 프로퍼티로 변경한 새로운 타입을 반환합니다.
구현
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};
예시
interface User {
name: string;
age: number;
}
interface ReadonlyUser {
readonly name: string;
readonly age: number;
}
Record<K, T>
K를 속성으로, T를 그 속성 값의 타입으로 갖는 새로운 타입을 반환합니다.
구현
type Record<K extends keyof any, T> = {
[P in K]: T;
};
제네릭의 extends는 부분집합으로 바라보면 해석이 편리합니다.
K는 keyof any의 부분집합 형태입니다.
예시
type User = 'kim' | 'so'
// Record<User, number>
interface RecordUser {
kim: number;
so: number;
}
Pick<T, K>
T에서 K의 집합으로 이루어진 새로운 타입을 반환합니다.
구현
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
};
K extends keyof T는 K가 T의 키 값으로 이루어진 유니온 타입으로부터 확장됨을 의미합니다.
예시
type Keys = 'name' | 'email';
interface User {
name: string;
age: number;
email: string;
}
// Pick<User, Keys>
interface PickUser {
name: string;
email: string;
}
Omit<T, K>
Pick과 반대로 T에서 K의 집합을 제외한 새로운 타입을 반환합니다.
구현
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
예시
type Keys = 'name' | 'email';
interface User {
name: string;
age: number;
email: string;
}
// Omit<User, Keys>
interface OmitUser {
age: number;
}
Exclude<T, U>
T에서 U를 제외한 새로운 타입을 반환합니다.
구현
type Exclude<T, U> = T extends U ? never : T;
예시
type T = string | number | boolean;
type U = number | boolean;
type V = Exclude<T, U>; // string
Extract<T, U>
Exclude와 반대로 T에서 U와 겹치는 타입을 반환합니다.
구현
type Partial<T> = {
[P in keyof T]?: T[P];
};
예시
type T = string | number | boolean;
type U = number | boolean;
type V = Extract<T, U>; // number | boolean
NonNullable<T>
T에서 null과 undefined를 제외한 새로운 타입을 반환합니다.
구현
type NonNullable<T> = T extends null | undefined ? never : T;
예시
type T = string | null | undefined;
type U = NonNullable<T>; // string
Parameters<T>
함수 타입 T의 매개변수 타입을 튜플 형태의 타입으로 반환합니다.
구현
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
예시
function func(a: string | number, b: boolean) {
return [a, b];
}
type T = Parameters<typeof func>; // [a: string | number, b: boolean]
ConstructorParameters<T>
클래스 타입 T의 매개변수 타입을 튜플 형태의 타입으로 반환합니다.
구현
type ConstructorParameters<T extends new (...args: any) => any> = T extends new (...args: infer P) => any ? P : never;
예시
class User {
constructor(
public name: string,
private age: number,
) {}
}
type T = ConstructorParameters<typeof User>; // [name: string, age: number]
ReturnType<T>
함수 타입 T의 반환 타입을 새로운 타입으로 반환합니다.
구현
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
예시
function func(a: string | number, b: boolean) {
return [a, b];
}
type T = ReturnType<typeof func>; // (string | number | boolean)[]
InstanceType<T>
클래스 타입 T의 인스턴스 타입을 반환합니다.
구현
type InstanceType<T extends new (...args: any) => any> = T extends new (...args: any) => infer R ? R : any;
예시
class User {
constructor(
public name: string,
private age: number,
) {}
}
type T = InstanceType<typeof User>; // User
ThisParameterType<T>
함수 타입 T의 명시적 this의 매개변수 타입을 새로운 타입으로 반환합니다.
예시
function toHex(this: Number) {
return this.toString(16);
}
function numberToString(n: ThisParameterType<typeof toHex>) { // Number
return toHex.apply(n);
}
OmitThisParameter<T>
함수 타입 T의 명시적 this의 매개변수 타입을 제외한 새로운 타입을 반환합니다.
예시
function toHex(this: Number) {
return this.toString(16);
}
const fiveToHex: OmitThisParameter<typeof toHex> = toHex.bind(5); // () => string
ThisType<T>
T의 this 컨텍스트를 명시적으로 설정합니다. 다만 별도의 타입을 반환하지 않습니다.
예시
interface User {
name: string;
getName: () => string;
}
function makeNeo(methods: ThisType<User>) {
return { name: 'Neo', ...methods } as User;
}
const neo = makeNeo({
getName() {
return this.name;
},
});
neo.getName(); // Neo
'프론트엔드 > TypeScript' 카테고리의 다른 글
[TypeScript] 제네릭 (Generic) (0) | 2022.06.07 |
---|---|
[TypeScript] Interface와 Type Alias의 차이점 (0) | 2022.06.06 |
[TypeScript] 타입 가드 (Type Guard) (0) | 2022.06.02 |
[TypeScript] 타입 단언 (Type Assertion) (0) | 2022.06.02 |
[TypeScript] 타입 종류 (0) | 2022.05.31 |