유틸리티 타입
Partial·Required·Readonly·Pick·Omit과 유니온·함수 변환 유틸리티로 기존 타입을 목적에 맞게 재구성합니다.
타입스크립트는 복잡한 타입 변환/조합을 쉽게 수행하도록 다양한 유틸리티 타입(Utility Types)을 내장하고 있습니다.
이 유틸리티 타입 대부분은
앞서 배운 조건부 타입과 매핑된 타입 개념(keyof, typeof, infer 등)을
기반으로 구현되어 있습니다.
유틸리티 타입은 기존 타입을 재활용하여 새로운 타입을 생성하는 데 탁월하며, 타입 정의의 반복을 줄이고 코드의 가독성 및 유지보수성을 크게 향상시킵니다.
이 절에서는 가장 자주 사용되는 주요 유틸리티 타입들을 살펴보겠습니다.
유틸리티 타입은 기존 타입을 복사해서 일부 속성을 선택, 제거, 필수화, 읽기 전용화하는 표준 도구입니다. `Partial`, `Pick`, `Omit`, `ReturnType`처럼 자주 쓰는 변환은 mapped type과 conditional type을 직접 매번 작성하는 일을 줄입니다.
- 객체 타입 변환 유틸리티
객체 타입의 속성을 수정하거나 특정 속성만 선택/제외할 때 사용하는 유틸리티 타입입니다. 유틸리티 타입(Utility Types)
- 유니온 및 함수 타입 변환 유틸리티
Exclude, Extract, ReturnType, Parameters는 유니온이나 함수 시그니처에서 필요한 부분만 뽑아냅니다. ReturnType
- 고급 유틸리티 타입 (일부)
Awaited, NonNullable, ThisParameterType처럼 비동기 값, nullable 제거, this 매개변수 처리에 쓰는 유틸리티도 함께 구분합니다. NonNullable
- 유틸리티 타입 기준
정확성 Partial, Pick, Omit은 기존 타입을 복사해 새 선언을 늘리는 대신 필수 여부와 속성 집합을 타입 수준에서 변환합니다. 비용 `Partial<T>`는 입력 일부만 받는 update payload에 적합하지만, 저장 직전에는 필수값 검증을 따로 해야 합니다. 확장성 `Pick<T, K>`와 `Omit<T, K>`은 API 응답, 폼 입력, 내부 모델을 같은 원본 타입에서 파생할 때 중복 선언을 줄입니다. 예외 `Required<T>`는 선택 속성을 모두 필수로 바꾸므로 실제 값이 채워지는 단계와 타입 변환 시점이 맞는지 확인해야 합니다.
- 정확성 Partial, Pick, Omit
기존 타입을 복사해 새 선언을 늘리는 대신 필수 여부와 속성 집합을 타입 수준에서 변환합니다.
- 비용 `Partial<T>`
입력 일부만 받는 update payload에 적합하지만, 저장 직전에는 필수값 검증을 따로 해야 합니다.
- 확장성 `Pick<T, K>`
`Omit<T, K>`은 API 응답, 폼 입력, 내부 모델을 같은 원본 타입에서 파생할 때 중복 선언을 줄입니다.
- 예외 `Required<T>`
선택 속성을 모두 필수로 바꾸므로 실제 값이 채워지는 단계와 타입 변환 시점이 맞는지 확인해야 합니다.
객체 타입 변환 유틸리티
Partial, Pick, Omit, Record 같은 도구는 원본 타입을 기준으로 optional, 선택, 제거, key/value 매핑을 수행한다.
- Partial<T>Partial<T> 모든 속성
optional로 바꿈
- Pick<T,K>Pick<T,K> 필요한 key만 선택
- Omit<T,K>Omit<T,K> 불필요한 key 제거
- Record<K,V>Record<K,V> key 집합
value 타입으로 새 객체 생성
| 구분 | 기준 |
|---|---|
| 폼 draft | Partial<User> |
| API projection | Pick<User, "id" | "name"> |
| 권한 제거 | Omit<User, "password"> |
객체 타입의 속성을 수정하거나 특정 속성만 선택/제외할 때 사용하는 유틸리티 타입입니다.
Partial<T>: T의 모든 속성을 선택적(Optional) 으로 만듭니다.
interface User {
id: number;
name: string;
email: string;
}
type PartialUser = Partial<User>;
/*
// PartialUser의 실제 타입:
type PartialUser = {
id?: number;
name?: string;
email?: string;
};
*/
const userUpdate: PartialUser = {
name: "새로운 이름",
email: "new@example.com"
}; // id는 필수가 아님폼 데이터 업데이트 등, 객체의 일부만 필요한 경우에 유용합니다.
Required<T>: T의 모든 속성을 필수(Required)로 만듭니다.
Partial의 반대입니다.
interface ProductConfig {
name?: string;
price?: number;
inStock?: boolean;
}
type FullProductConfig = Required<ProductConfig>;
/*
// FullProductConfig의 실제 타입:
type FullProductConfig = {
name: string;
price: number;
inStock: boolean;
};
*/
// const config1: FullProductConfig = { name: "Test" }; // Error: 'price' 및 'inStock' 속성이 누락됨
const config2: FullProductConfig = { name: "Monitor", price: 300000, inStock: true };Readonly<T>: T의 모든 속성을 읽기 전용(readonly) 으로 만듭니다.
interface Point {
x: number;
y: number;
}
type ImmutablePoint = Readonly<Point>;
/*
// ImmutablePoint의 실제 타입:
type ImmutablePoint = {
readonly x: number;
readonly y: number;
};
*/
const p: ImmutablePoint = { x: 10, y: 20 };
// p.x = 15; // Error: Cannot assign to 'x' because it is a read-only property.객체의 불변성을 강제할 때 사용됩니다.
Pick<T, K>: T에서 K 타입에 해당하는 속성들만 선택하여 새로운 타입을 만듭니다.
interface Todo {
id: number;
title: string;
description: string;
completed: boolean;
createdAt: Date;
}
type TodoPreview = Pick<Todo, 'id' | 'title' | 'completed'>;
/*
// TodoPreview의 실제 타입:
type TodoPreview = {
id: number;
title: string;
completed: boolean;
};
*/
const todoItem: TodoPreview = {
id: 1,
title: "타입스크립트 학습",
completed: false
};특정 API 응답에서 필요한 데이터만 추출하거나, 특정 뷰에 필요한 데이터 모델을 정의할 때 유용합니다.
Omit<T, K>: T에서 K 타입에 해당하는 속성들을 제외하여 새로운 타입을 만듭니다.
type TodoWithoutDescription = Omit<Todo, 'description'>;
/*
// TodoWithoutDescription의 실제 타입:
type TodoWithoutDescription = {
id: number;
title: string;
completed: boolean;
createdAt: Date;
};
*/
const todoDisplay: TodoWithoutDescription = {
id: 2,
title: "회의 준비",
completed: true,
createdAt: new Date()
};Pick과 상호 보완적으로 사용되며, 특정 속성을 제외한 나머지가 필요할 때 유용합니다.
Record<K, T>: K 타입의 속성 이름을 가지며, 모든 속성 값이 T 타입인 객체 타입을 만듭니다.
딕셔너리 또는 맵 타입을 정의할 때 사용됩니다.
type PageInfo = {
title: string;
url: string;
};
type Page = "home" | "about" | "contact";
type SitePages = Record<Page, PageInfo>;
/*
// SitePages의 실제 타입:
type SitePages = {
home: { title: string; url: string; };
about: { title: string; url: string; };
contact: { title: string; url: string; };
};
*/
const site: SitePages = {
home: { title: "메인 페이지", url: "/" },
about: { title: "회사 소개", url: "/about" },
contact: { title: "연락처", url: "/contact" }
};동적으로 키가 생성되거나, 특정 키 집합에 대해 일관된 값 타입을 강제할 때 강력합니다.
유니온 및 함수 타입 변환 유틸리티
유니온 타입이나 함수 타입을 다룰 때 유용한 유틸리티입니다.
Exclude<T, U>: T에서 U에 할당 가능한 타입을 제외합니다. (5장 2절 "조건부 타입"에서 설명)
type MyColors = "red" | "green" | "blue" | "black" | "white";
type PrimaryColors = Exclude<MyColors, "black" | "white">; // type PrimaryColors = "red" | "green" | "blue"Extract<T, U>: T에서 U에 할당 가능한 타입만 추출합니다. (5장 2절 "조건부 타입"에서 설명)
type MixedValue = string | number | boolean | (() => void);
type OnlyFunctions = Extract<MixedValue, Function>; // type OnlyFunctions = () => voidNonNullable<T>: T에서 null과 undefined를 제외합니다. (5장 2절 "조건부 타입"에서 설명)
type NullableString = string | null | undefined;
type NonNullString = NonNullable<NullableString>; // type NonNullString = stringParameters<T>: 함수 타입 T의 매개변수 타입을 튜플로 추출합니다.
type MyFunction = (name: string, age: number) => string;
type Params = Parameters<MyFunction>; // type Params = [name: string, age: number]
type NoParams = Parameters<() => void>; // type NoParams = []ReturnType<T>: 함수 타입 T의 반환 타입을 추출합니다.
type MyFunctionReturn = ReturnType<MyFunction>; // type MyFunctionReturn = string
type AsyncReturn = ReturnType<() => Promise<number>>; // type AsyncReturn = Promise<number>내장 유틸리티 타입은 이름은 많지만, 내부 원리는 매핑된 타입, 조건부 타입, infer 추론으로 묶어 볼 수 있습니다.
고급 유틸리티 타입 (일부)
타입스크립트에는 이 외에도 특정 상황에서 유용한 고급 유틸리티 타입들이 있습니다.
ThisParameterType<T>: 함수 타입 T의 this 매개변수 타입을 추출합니다.
function toHex(this: Number, decimal: number): string {
return this.toString(16) + decimal.toString(16);
}
type ThisType = ThisParameterType<typeof toHex>; // type ThisType = NumberOmitThisParameter<T>: 함수 타입 T에서 this 매개변수를 제거한 새로운 함수 타입을 만듭니다.
type NoThisToHex = OmitThisParameter<typeof toHex>; // type NoThisToHex = (decimal: number) => string
// const simplifiedHex: NoThisToHex = toHex; // Error: 'this' 매개 변수가 포함된 함수는 바인딩되어야 합니다.
// 타입만 제거할 뿐 런타임 동작이 변하는 것은 아닙니다.Awaited<T> (TypeScript 4.5+): Promise와 같은 awaitable 타입의 최종 resolved 값을 재귀적으로 추출합니다.
type PromiseOfNumbers = Promise<Promise<number>>;
type Result = Awaited<PromiseOfNumbers>; // type Result = number
type ValueOrPromise = string | Promise<number>;
type AwaitedValueOrPromise = Awaited<ValueOrPromise>; // type AwaitedValueOrPromise = string | number비동기 함수의 반환 타입을 정확히 추론할 때 매우 유용합니다.
아래 다이어그램은 하나의 원본 타입에서 수정 DTO, 공개 DTO, 함수 계약, 비동기 결과 타입을 파생시키는 조합을 보여줍니다.
내장 유틸리티 타입은 원본 모델을 복사하지 않고, 화면 입력과 API 응답, 함수 계약에 맞게 다시 조립한다.
- Partial<Pick<User, "name" | "email">>
수정 폼은 바꿀 수 있는 필드만 고르고 모두 선택적으로 만든다.
- Omit<User, "password">
외부 응답에서 비밀번호 같은 내부 필드를 타입 단계에서 제외한다.
- Record<Page, PageInfo>
정해진 페이지 키마다 같은 형태의 메타데이터가 존재하게 한다.
- Parameters와 ReturnType
핸들러의 인자와 결과 타입을 테스트, mock, 래퍼 함수가 공유한다.
- Awaited<ReturnType<typeof fetchUser>>
비동기 함수가 최종적으로 resolve하는 값 타입만 꺼내 재사용한다.
유틸리티 타입은 원본 타입을 직접 바꾸지 않고 목적별 계약을 파생시키는 도구입니다.
다음 기준표는 API 입력, 공개 응답, 함수 계약, 비동기 결과에 맞는 유틸리티 선택을 정리합니다.
원본 타입을 목적별 계약으로 파생시킬 때는 바꾸려는 축을 먼저 고르면 유틸리티가 자연스럽게 정해집니다.
- Partial수정 입력
PATCH DTO처럼 일부 필드만 받을 때 선택 속성으로 바꿉니다.
- Pick/Omit공개 응답
노출할 필드를 고르거나 민감한 필드를 제거합니다.
- ReturnType함수 계약
함수의 반환 타입을 재사용해 호출부와 구현을 맞춥니다.
- Awaited비동기 결과
Promise가 중첩되어도 최종 resolved 값을 추출합니다.
- 필수화
폼 제출 이후에는 `Required`로 빠진 필드를 막습니다.
유틸리티 타입은 기존 타입을 선택, 제외, 부분화, 읽기 전용화하는 재사용 가능한 타입 변환 도구입니다.
내장 유틸리티 타입을 사용하면 반복적인 타입 선언을 줄이고, 객체 구조 변화에 맞춰 타입 계약을 더 일관되게 유지할 수 있습니다.
다음 다이어그램은 TypeScript 유틸리티 타입을 변환 대상별로 묶어 보는 선택표입니다.
Partial, Pick, Omit, Exclude, ReturnType처럼 내장 유틸리티는 객체와 union, 함수 타입 변환을 짧고 일관되게 표현합니다.
- 정책 변경
객체 속성 Partial, Required, Readonly는 같은 객체 모양의 속성 정책을 바꿉니다. Partial<T>
- 모양 재구성
키 선택 Pick과 Omit은 필요한 필드만 남기거나 특정 필드를 제외합니다. Pick<T, K>
- 후보 정리
union 필터 Exclude와 Extract는 union 멤버를 조건에 따라 제거하거나 남깁니다. Exclude<U, V>
- 입출력 재사용
함수 추출 Parameters와 ReturnType은 기존 함수 타입의 인자와 결과를 가져옵니다. ReturnType<F>
이 다이어그램은 유틸리티 타입 학습을 객체 변환, 유니온 필터, 함수 추출 기준으로 마무리합니다.
Partial, Pick, Omit, Record, ReturnType 같은 내장 유틸리티는 자주 쓰는 타입 조작을 짧고 일관되게 표현합니다.
- 속성 선택과 변경
객체 변환 Partial, Required, Pick, Omit으로 객체 타입의 필수 여부와 포함 속성을 조절합니다. Pick<T, K>
- 키 집합과 값 타입
맵 구조 Record는 정해진 키 집합마다 같은 값 타입을 강제해 누락된 키와 잘못된 값 타입을 잡습니다. Record<K,V>
- 후보 포함과 제외
유니온 정리 Exclude와 Extract로 유니온 멤버 중 필요한 타입만 남기거나 제거합니다. Exclude
- 시그니처 재사용
함수 추출 Parameters와 ReturnType으로 기존 함수 타입에서 인자와 반환 타입을 가져옵니다. ReturnType
아래 다이어그램은 자주 쓰는 유틸리티 타입을 객체 변환, 유니온 필터, 함수 추출 기준으로 묶습니다.
유틸리티 타입은 조건부 타입과 매핑된 타입으로 만든 표준 도구이며 반복되는 타입 변환을 짧게 표현합니다.
- 객체 변환Partial과 Required
객체 변환 속성의 선택 여부나 읽기 전용 여부를 일괄적으로 바꿉니다. Readonly<T>
- 속성 선택Pick과 Omit
속성 선택 큰 객체 타입에서 필요한 필드만 고르거나 특정 필드를 제외합니다. Pick<User, "id">
- 유니온 필터Exclude와 Extract
유니온 필터 유니온 멤버 중 제거하거나 남길 타입을 조건으로 걸러냅니다. Exclude<T, null>
- 함수 추출ReturnType과 Parameters
함수 추출 함수 타입에서 반환값 또는 매개변수 튜플을 꺼내 재사용합니다. ReturnType<typeof fn>
아래 다이어그램은 유틸리티 타입을 실제 코드에 적용하기 전에 설정 위치, 타입 해석, 빌드 결과를 확인합니다.