TypeScript 유틸리티 타입¶
개요¶
객체의 일부 속성만 받거나, 모든 속성을 읽기 전용으로 만들거나, 함수의 파라미터 타입을 뽑아내야 할 때가 있어요. 매번 하나하나 타입을 새로 적기보다, TypeScript가 기본 제공하는 유틸리티 타입으로 기존 타입을 변환하면 코드가 훨씬 간결해져요. 이 유틸리티들은 전역으로 사용할 수 있어요.
핵심 개념¶
가장 자주 쓰는 몇 가지로 시작해요.
Partial<Type>— 모든 속성을 선택적(optional)으로 바꿔요. 객체의 일부만 갱신하는 함수 시그니처를 만들 때 유용해요.
function updateTodo(todo: Todo, fieldsToUpdate: Partial<Todo>) {
return { ...todo, ...fieldsToUpdate };
}
Required<Type>— 모든 속성을 필수로 바꿔요.Partial의 반대예요.Readonly<Type>— 모든 속성을readonly로 바꿔요. 재할당 시도가 컴파일 타임에 걸려요.Object.freeze가 반환하는 타입을 표현할 때도 써요.Pick<Type, Keys>/Omit<Type, Keys>— 원하는 속성만 골라내거나, 특정 속성만 제거해요.Pick<Todo, 'title' | 'completed'>처럼 필요한 부분만 뽑을 수 있죠.Record<Keys, Type>— 키는 Keys, 값은 Type인 객체 타입을 만들어요. enum이나 리터럴 유니온을 키로 쓰는 맵을 만들 때 유용해요.Exclude<Type, Union>/Extract<Type, Union>— 유니온에서 특정 멤버를 빼거나, 조건에 맞는 멤버만 남겨요.NonNullable<Type>—null과undefined를 제거해요.Parameters<Type>/ReturnType<Type>— 함수 타입의 파라미터를 튜플로, 반환 타입을 그대로 뽑아요.typeof와 함께 쓰면 기존 함수에서 타입을 재사용하기 좋아요.Awaited<Type>—async의await처럼Promise를 재귀적으로 풀어요.Awaited<Promise<string>>은string이 되죠.- 문자열 조작 타입 —
Uppercase,Lowercase,Capitalize,Uncapitalize가 템플릿 리터럴 타입과 함께 쓰여요.
유틸리티 타입은 결국 "맵드 타입"·"조건부 타입" 같은 TypeScript 문법으로 정의된 타입들이에요. 기본 제공 유틸리티만으로 부족하면 같은 원리로 직접 만들 수도 있어요. 그 시작점이 바로 위 유틸리티들이죠.
실제 적용(데이터스케쳐스 관점)¶
캔버스와 웹빌더 코드베이스에서 유틸리티 타입은 타입 중복을 줄이는 주 무기예요. 예를 들어 "노드 전체 타입은 있지만 화면에 그리는 데는 좌표와 라벨만 필요하다"면 Pick<CanvasNode, 'x' | 'y' | 'type' | 'label'>로 표시용 타입을 즉석에서 만들어요. Omit은 "저장용 필드(id)는 제외한 입력용 타입" 같은 걸 만들 때 자주 쓰이죠.
또 "모든 속성을 선택적으로 받는 폼 상태"는 Partial, "한번 만들면 바뀌면 안 되는 설정"은 Readonly로 막아요. API 응답이나 함수 시그니처가 바뀔 때 Parameters·ReturnType으로 기존 타입을 따라가면, 원본을 고칠 때 파생 타입이 자동으로 맞춰져요. 이렇게 유틸리티 타입을 쓰면 도메인 타입 한 곳만 고치면 다른 곳이 일관되게 따라가서, 컴파일 타임 검사를 그대로 보장받아요.
더 알아보기¶
- 공식 문서 (1차): TypeScript — Utility Types, 맵드 타입, 조건부 타입
- 상위 개념: TypeScript
- 관련 챕터: 인터페이스 vs 타입 · 타입 추론