본격적인 업무에 들어가기 앞서, 타입스크립트에서 유용하게 사용할 수 있는 유틸리티 타입 종류에 대해 정리했다.
유틸리티 타입 종류는 아래 타입스크립트 공식 문서를 참고했다.
일반 유틸리티 타입
Awaited<T>
Promise<?> 형태의 T 타입을 전달받아, 해당 Promise가 반환하는 리턴값의 타입을 반환한다.
async ~ await의 await 키워드와 유사한 기능을 담당한다.
type A = Awaited<Promise<string>>; // type A = string
type B = Awaited<Promise<Promise<number>>>; // type B = number
type C = Awaited<boolean | Promise<number>>; // type C = number | boolean
Partial<T>
T 타입의 일부 프로퍼티만 가질 수 있는 타입(subset)을 반환한다.
모든 프로퍼티는 optional로 취급되며, 모든 프로퍼티를 갖지 않는 빈 객체{ }도 허용된다.
interface Point {
x: number;
y: number;
}
let pointPart: Partial<Point> = {}; // x와 y는 선택적 프로퍼티
pointPart.x = 10;
Required<T>
T 타입의 모든 프로퍼티를 필수로 갖는 타입을 반환한다.
기존 타입 내의 모든 optional 프로퍼티는 필수 속성으로 변경되며, 하나의 프로퍼티라도 누락되면 에러가 발생한다.
interface Car {
make: string;
model: string;
mileage?: number;
}
let myCar: Required<Car> = {
make: 'Ford',
model: 'Focus',
mileage: 12000, // mileage는 optional이 아닌 필수 프로퍼티
};
Readonly<T>
T 타입의 모든 프로퍼티를 readonly(읽기 전용)로 변환한 타입을 반환한다.
readonly 타입을 가진 값은 수정이 불가능하므로, 해당 타입의 값을 변경하게 되면 에러가 발생한다.
interface Todo {
title: string;
}
const todo: Readonly<Todo> = {
title: 'Delete inactive users',
};
todo.title = 'Hello'; // readonly 타입이므로 Error!
Record<K, T>
K를 key로, T를 type으로 하는 새로운 타입을 반환한다.
특정 타입만 키 또는 값으로 갖는 타입을 선언하고자 할 때 사용할 수 있다.
type CatName = "miffy" | "boris" | "mordred";
interface CatInfo {
age: number;
breed: string;
}
const cats: Record<CatName, CatInfo> = {
miffy: { age: 10, breed: "Persian" },
boris: { age: 5, breed: "Maine Coon" },
mordred: { age: 16, breed: "British Shorthair" },
};
K 타입으로 string, number, symbol을 사용할 경우에는 다음과 같이 선언해도 Record<K, T>로 선언한 타입과 동일하게 사용할 수 있다.
const nameAgeMap: Record<string, number> = {
'Alice': 21,
'Bob': 25
};
// 위의 예제와 동일한 결과 타입을 가짐
const nameAgeMap: { [key: string]: number } = {
'Alice': 21,
'Bob': 25
};
Pick<T, U>
T 타입에서 2번째 인자로 전달한 타입에 지정된 키만 프로퍼티로 갖는 새로운 타입을 반환한다.
2번째 인자로 지정하는 타입은 단일 타입도 가능하고 아래 예시처럼 유니온 타입으로도 지정할 수 있다.
interface Todo {
title: string;
description: string;
completed: boolean;
}
type TodoPreview = Pick<Todo, "title" | "completed">;
const todo: TodoPreview = { // title, completed 프로퍼티만 갖는 TodoPreview 타입
title: "Clean room",
completed: false,
};
Omit<T, U>
T 타입에서 2번째 인자로 전달한 유니온에 지정된 키만 프로퍼티로 갖지 않는 새로운 타입을 반환한다.
Pick<T, U> 유틸 타입과 정확히 반대의 기능을 수행한다.
interface Todo {
title: string;
description: string;
completed: boolean;
createdAt: number;
}
type TodoPreview = Omit<Todo, "description">;
const todo: TodoPreview = { // description 프로퍼티가 빠진 타입 TodoPreview
title: "Clean room",
completed: false,
createdAt: 1615544252770,
};
type TodoInfo = Omit<Todo, "completed" | "createdAt">;
const todoInfo: TodoInfo = { // completed, createdAt이 빠진 타입 TodoInfo
title: "Pick up kids",
description: "Kindergarten closes at 5pm",
};
Exclude<T, U>
T 타입에서 U 타입과 공통되는 프로퍼티를 제외한 나머지 프로퍼티를 타입으로 추출하여 반환한다.
벤 다이어그램의 T - U와 동일한 기능을 수행한다.
type T0 = Exclude<"a" | "b" | "c", "a">; // type T0 = "b" | "c"
type T1 = Exclude<"a" | "b" | "c", "a" | "b">; // type T1 = "c"
type T2 = Exclude<string | number | (() => void), Function>; // type T2 = string | number
Extract<T, U>
T 타입에서 U 타입과 공통되는 모든 프로퍼티를 타입으로 추출하여 반환한다.
벤 다이어그램의 T ∩ U(단, T > U)와 유사한 기능을 수행한다.
type T0 = Extract<"a" | "b" | "c", "a" | "f">; // type T0 = "a"
type T1 = Extract<string | number | (() => void), Function>; // type T1 = () => void
NonNullable<Type>
T 타입에서 Nullable한 타입인 null, undefined를 제외한 타입을 반환한다.
type T0 = NonNullable<string | number | undefined>; // type T0 = string | number
type T1 = NonNullable<string[] | null | undefined>; // type T1 = string[]
Parameters<T>
함수 타입 T의 매개변수 타입을 튜플(tuple) 형태로 반환한다.
튜플 내의 타입은 배열처럼 인덱스로 접근 가능하며, 함수 타입이 아닌 타입을 T로 전달하면 에러가 발생한다.
declare function f1(arg1: { a: number; b: string }, arg2?: string): void;
type T0 = Parameters<() => string>; // type T0 = []
type T1 = Parameters<(s: string) => void>; // type T1 = [s: string]
type T2 = Parameters<<T>(arg: T) => T>; // type T2 = [arg: unknown]
type T3 = Parameters<typeof f1>; // type T3 = [arg1: { a: number; b: string; }, arg2?: string | undefined]
type T4 = Parameters<any>; // type T4 = unknown[]
type T5 = Parameters<never>; // type T5 = never
type T6 = Parameters<string>; // Error, type T6 = never
type T7 = Parameters<Function>; // Error, type T7 = never
ConstructorParameters<T>
생성자 함수 타입 T의 매개변수 타입을 튜플(tuple) 형태로 반환한다.
Parameters<T>와 유사하지만, 일반 함수나 생성자 함수 타입이 아닌 타입을 T로 전달하면 에러가 발생한다.
type T0 = ConstructorParameters<ErrorConstructor>; // type T0 = [message?: string]
type T1 = ConstructorParameters<FunctionConstructor>; // type T1 = string[]
type T2 = ConstructorParameters<RegExpConstructor>; // type T2 = [pattern: string | RegExp, flags?: string]
type T3 = ConstructorParameters<any>; // type T3 = unknown[]
type T4 = ConstructorParameters<Function>; // Error, type T4 = never
ReturnType<T>
함수 타입 T의 리턴 타입 유형을 반환한다.
declare function f1(): { a: number; b: string };
type T0 = ReturnType<() => string>; // type T0 = string
type T1 = ReturnType<(s: string) => void>; // type T1 = void
type T2 = ReturnType<<T>() => T>; // type T2 = unknown
type T3 = ReturnType<<T extends U, U extends number[]>() => T>; // type T3 = number[]
type T4 = ReturnType<typeof f1>; // type T4 = { a: number; b: string; }
type T5 = ReturnType<any>; // type T5 = any
type T6 = ReturnType<never>; // type T6 = never
type T7 = ReturnType<string>; // Error, type T7 = any
type T8 = ReturnType<Function>; // Error, type T8 = any
InstanceType<T>
생성자 함수 타입 T의 인스턴스 타입으로 구성된 타입을 반환한다.
ConstructorParameters<T>와 마찬가지로 생성자 함수가 아닌 함수 타입을 전달하면 에러가 발생한다.
class C {
x = 0;
y = 0;
}
type T0 = InstanceType<typeof C>; // type T0 = C
type T1 = InstanceType<any>; // type T1 = any
type T2 = InstanceType<never>; // type T2 = never
type T3 = InstanceType<string>; // Error, type T3 = any
type T4 = InstanceType<Function>; // Error, type T4 = any
ThisParameterType<T>
함수 타입 T의 매개변수 및 반환 타입에 this 매개변수가 없을 경우 unknown을 반환한다.
function toHex(this: Number) {
return this.toString(16);
}
function numberToString(n: ThisParameterType<typeof toHex>) {
return toHex.apply(n);
}
OmitThisParameter<T>
함수 타입 T에서 this 매개변수를 제거한 타입을 반환한다.
OmitThisParameter<T>을 사용하기 위해서는 strictFunctionTypes 옵션을 활성화해야 한다.
function toHex(this: number) {
return this.toString(16);
}
const fiveToHex: OmitThisParameter<typeof toHex> = toHex.bind(5);
console.log(fiveToHex());
ThisType<T>
ThisType은 새로운 타입을 반환하는 것이 아닌 문맥상 this에 대한 마커 역할을 한다는 점에서 다른 유틸리티 타입들과는 차이가 있다.
ThisType<T>을 사용하기 위해서는 noImplicitThis 옵션을 활성화해야 한다.
type MyExclude<T, U extends T> = { [key in keyof T]: T[key] }
type Result = MyExclude<'a' | 'b' | 'c', 'a'> // 'b' | 'c'
type ObjectDescriptor<D, M> = {
data?: D;
methods?: M & ThisType<D & M>; // this에 메소드 M 타입 지정 && this의 타입을 명시적으로 D & M으로 지정
};
function makeObject<D, M>(desc: ObjectDescriptor<D, M>): D & M {
let data: object = desc.data || {};
let methods: object = desc.methods || {};
return { ...data, ...methods } as D & M;
}
let obj = makeObject({
data: { x: 0, y: 0 },
methods: {
moveBy(dx: number, dy: number) {
this.x += dx; // ThisType으로 바인딩된 this의 x, y 프로퍼티에 접근
this.y += dy;
},
},
});
obj.x = 10;
obj.y = 20;
obj.moveBy(5, 5);
string 타입을 위한 유틸리티 타입
Uppercase<StringType>
문자열 형태의 타입을 전달하면 해당 문자열 값을 모두 대문자로 변환한 새로운 타입을 반환한다.
type Greeting = "Hello, world"
type ShoutyGreeting = Uppercase<Greeting> // type ShoutyGreeting = "HELLO, WORLD"
type ASCIICacheKey<Str extends string> = `ID-${Uppercase<Str>}`
type MainID = ASCIICacheKey<"my_app"> // type MainID = "ID-MY_APP"
Lowercase<StringType>
문자열 형태의 타입을 전달하면 해당 문자열 값을 모두 소문자로 변환한 새로운 타입을 반환한다.
type Greeting = "Hello, world"
type QuietGreeting = Lowercase<Greeting> // type QuietGreeting = "hello, world"
type ASCIICacheKey<Str extends string> = `id-${Lowercase<Str>}`
type MainID = ASCIICacheKey<"MY_APP"> // type MainID = "id-my_app"
Capitalize<StringType>
문자열 형태의 타입을 전달하면 해당 문자열 값의 앞 글자를 대문자로 변환한 새로운 타입을 반환한다.
type LowercaseGreeting = "hello, world";
type Greeting = Capitalize<LowercaseGreeting>; // type Greeting = "Hello, world"
Uncapitalize<StringType>
문자열 형태의 타입을 전달하면 해당 문자열 값의 앞 글자를 소문자로 변환한 새로운 타입을 반환한다.
type UppercaseGreeting = "HELLO WORLD";
type UncomfortableGreeting = Uncapitalize<UppercaseGreeting>; // type UncomfortableGreeting = "hELLO WORLD"
'Language > Javascript' 카테고리의 다른 글
Speculation Rules API - MPA에서도 빠른 페이지 전환 제공하기 (0) | 2024.06.13 |
---|---|
Javascript - ECMAScript 2023(ES14)에 추가된 기능 (0) | 2023.06.05 |
Javascript - a 태그 알아보기 (0) | 2022.07.10 |
Javascript - object와 array 타입 변환 / 일부 값만 뽑아오기 (0) | 2022.06.11 |
Javascript - sort 함수를 이용한 데이터 정렬 (0) | 2022.05.10 |