Skip to content

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>nullundefined를 제거해요.
  • Parameters<Type> / ReturnType<Type> — 함수 타입의 파라미터를 튜플로, 반환 타입을 그대로 뽑아요. typeof와 함께 쓰면 기존 함수에서 타입을 재사용하기 좋아요.
  • Awaited<Type>asyncawait처럼 Promise를 재귀적으로 풀어요. Awaited<Promise<string>>string이 되죠.
  • 문자열 조작 타입Uppercase, Lowercase, Capitalize, Uncapitalize가 템플릿 리터럴 타입과 함께 쓰여요.

유틸리티 타입은 결국 "맵드 타입"·"조건부 타입" 같은 TypeScript 문법으로 정의된 타입들이에요. 기본 제공 유틸리티만으로 부족하면 같은 원리로 직접 만들 수도 있어요. 그 시작점이 바로 위 유틸리티들이죠.

실제 적용(데이터스케쳐스 관점)

캔버스와 웹빌더 코드베이스에서 유틸리티 타입은 타입 중복을 줄이는 주 무기예요. 예를 들어 "노드 전체 타입은 있지만 화면에 그리는 데는 좌표와 라벨만 필요하다"면 Pick<CanvasNode, 'x' | 'y' | 'type' | 'label'>로 표시용 타입을 즉석에서 만들어요. Omit은 "저장용 필드(id)는 제외한 입력용 타입" 같은 걸 만들 때 자주 쓰이죠.

또 "모든 속성을 선택적으로 받는 폼 상태"는 Partial, "한번 만들면 바뀌면 안 되는 설정"은 Readonly로 막아요. API 응답이나 함수 시그니처가 바뀔 때 Parameters·ReturnType으로 기존 타입을 따라가면, 원본을 고칠 때 파생 타입이 자동으로 맞춰져요. 이렇게 유틸리티 타입을 쓰면 도메인 타입 한 곳만 고치면 다른 곳이 일관되게 따라가서, 컴파일 타임 검사를 그대로 보장받아요.

더 알아보기