
TypeScript는 공통 타입 변환을 용이하게 하기 위해 유틸리티 타입을 제공한다.
유틸리티 타입은 전역으로 사용 가능하다.
Partial<T>프로퍼티를 선택적(부분적)으로 만드는 타입을 구성한다. 주어진 타입의 모든 하위 타입 집합을 나타내는 타입을 반환한다.
아래 예제 코드에서 updateTodo 함수 호출 시 title을 제외한 description 호출하여 사용이 가능한 것을 확인할 수 있다.
interface Todo {
title: string;
description: string;
}
const updateTodo = (todo: Todo, fieldsToUpdate: Partial<Todo>) => {
return { ...todo, ...fieldsToUpdate };
};
const todo1 = {
title: 'organize desk',
description: 'clear clutter',
};
const todo2 = updateTodo(todo1, {
description: 'throw out trash',
});
Readonly<T>프로퍼티를 읽기 전용(readonly)으로 설정한 타입을 구성한다.
아래 예제 코드에서 todo 객체의 프로퍼티에 재할당을 방지하기 위해 Readonly 타입을 사용했다.
interface Todo {
title: string;
}
const todo: Readonly<Todo> = {
title: 'Delete inactive users',
};
todo.title = 'Hello'; // Error: Cannot as sign to 'title' because it is a read-only property
프로퍼티의 집합 K로 타입을 구성한다. 타입의 프로퍼티들을 다른 타입에 매핑 시키는데 사용한다.
아래 예제 코드를 보면 변수 x는 Record 타입 Page, PageInfo로 구성되어 있다. home의 value를 보면 object subTitle을 선언했는데 PageInfo에는 subTitle이라는 프로퍼티가 없으므로 에러가 발생하게 된다.
또한 Page에는 'home', 'about', 'contact'라는 변수들만 선언되어 있는데 변숫값으로 main을 선언했기 때문에 마찬가지로 에러가 발생하는 것을 확인할 수 있다.
interface PageInfo {
title: string;
}
type Page = 'about' | 'contact' | 'home';
const x: Record<Page, PageInfo> = {
about: { title: 'about' },
contact: { title: 'contact' },
home: { subTitle: 'home' }, // Error: '{subTitle: string}' is not assignable
main: { title: 'home' }, // Error: main is not assignable to type 'Page'
};
참고
모든 프로퍼티 중에서 선택한 K의 집합만으로 타입을 구성한다.
아래 예제 코드를 보면 타입 TodoPreview는 Todo 인터페이스의 title과 completed 프로퍼티만 선택해 타입을 구성했다. 하지만 todo 변수에 선택하지 않은 description key, value를 선언했기 때문에 에러가 발생하는 것을 확인할 수 있다.
interface Todo {
title: string;
description: string;
completed: boolean;
}
type TodoPreview = Pick<Todo, 'title' | 'completed'>;
const todo: TodoPreview = {
title: 'Clean room',
completed: false,
description: 'description', // Error: 'description' is not assignable to type
};
Omit은 Pick 과는 반대로 모든 프로퍼티 중에서 선택한 K를 제거한 타입을 구성한다.
아래 예제 코드를 보면 타입 TodoPreview는 Todo 인터페이스의 description 프로퍼티를 선택하여 제거했다. 따라서 todo 변수에 제거된 description 변수를 선언하면 에러가 발생하는 것을 확인할 수 있다.
interface Todo {
title: string;
description: string;
completed: boolean;
}
type TodoPreview = Omit<Todo, 'description'>;
const todo: TodoPreview = {
title: 'Clean room',
completed: false,
description: 'description', // Error: 'description' is not assignable to type
};
T에서 U에 할당할 수 있는 모든 속성을 제외한 타입을 구성한다. 즉, T에서 U를 제외한 타입만 사용할 수 있다.
아래 예제 코드에서 타입 T0은 a, b, c 프로퍼티 중 a를 제외했기 때문에 b와 c 타입만 사용 가능한 것을 확인할 수 있다.
type T0 = Exclude<'a' | 'b' | 'c', 'a'>; // 'b' | 'c'
type T1 = Exclude<'a' | 'b' | 'c', 'a' | 'b'>; // 'C'
type T2 = Exclude<string | number | (() => void), Function>; // string | number
T에서 U에 할당할 수 있는 모든 속성을 추출하여 타입을 구성한다. 즉 T와 U에 모두 존재하는(겹치는) 타입만 사용할 수 있다.
아래 예제 코드에서 타입 T0은 a, b, c 프로퍼티 중 a와 f를 추출했는데 f 타입은 존재하지 않기 때문에 a 타입만 구성이 되는 것을 확인할 수 있다.
type T0 = Extract<'a' | 'b' | 'c', 'a' | 'f'>; // 'a'
type T1 = Extract<string | number | (() => void), Function>; // '() => void'
NonNullable<T>type T0 = NonNullable<string | number | undefined>; // string | number
type T1 = NonNullable<string[] | null | undefined>; // string[]
Parameters<T>declare function f1(arg: { a: number; b: string }): void;
type T0 = Parameters<() => string>; // []
type T1 = Parameters<(s: string) => void>; // [string]
type T2 = Parameters<<T>(arg: T) => T>; // [unknown]
type T3 = Parameters<typeof f1>; // [{a: number, b: string}]
type T4 = Parameters<any>; // unknown[]
type T5 = Parameters<never>; // never
type T6 = Parameters<string>; // 오류
type T7 = Parameters<Function>; // 오류
ConstructorParameters<T>생성자 함수 타입의 모든 매개변수 타입을 추출한다. 모든 매개변수 타입을 가지는 튜플 타입(T가 함수가 아닌 경우 never)을 생성한다.
아래 예제 코드의 T12 타입은 인터페이스 I1 ConstructorParameters 타입을 선언했다. 인터페이스 I1의 매개변수는 string argument 하나만 존재하므로 string 값을 가지는 튜플 타입을 구성하는 것을 확인할 수 있다.
따라서 function f1에 타입 T12를 선언했을 때 a 변수는 index 1을 가지고 있지 않기 때문에 a[1]을 선언했을 때 타입 에러가 발생하게 된다.
type T10 = ConstructorParameters<ErrorConstructor>; // [(string | undefined)?]
type T11 = ConstructorParameters<FunctionConstructor>; // string[]
type T12 = ConstructorParameters<RegExpConstructor>; // (string, [string | undefined]?)
interface I1 {
new (args: string): Function;
}
type T12 = ConstructorParameters<I1>; // [string]
function f1(a: T12) {
a[0];
a[1]; // Error: Tuple type '[args: string]' of length '1' has no element at index '1'.
}
ReturnType<T>declare function f1(): { a: number; b: string };
type T0 = ReturnType<() => string>; // string
type T1 = ReturnType<(s: string) => void>; // void
type T2 = ReturnType<(<T>() => T)>; // {}
type T3 = ReturnType<(<T extends U, U extends number[]>() => T)>; // number[]
type T4 = ReturnType<typeof f1>; // {a: number, b: string}
type T5 = ReturnType<any>; // any
type T6 = ReturnType<never>; // any
type T7 = ReturnType<string>; // 오류
type T8 = ReturnType<Function>; // 오류
Required<T>T의 모든 프로퍼티가 필수로 설정된 타입을 구성한다.
아래 예제 코드를 보면 인터페이스 Props는 a와 b 프로퍼티를 옵셔널로 설정했지만 유틸리티 타입을 Required로 설정했기 때문에 b 프로퍼티를 설정하지 않아서 에러가 발생하는 것을 확인할 수 있다.
interface Props {
a?: number;
b?: string;
}
const obj: Props = { a: 5 };
const obj2: Required<Props> = { a: 5 }; // Error: Property 'b' is missing in type '{a: number}'