TypeScript 유틸리티 타입으로 API 응답 타입 정제하기

문제 상황

회사 API가 동일한 User 엔터티를 상황별로 다른 필드와 함께 반환한다. 목록 조회와 상세 조회의 응답 구조가 달라서 타입을 별도로 정의했더니 중복이 심했다.

interface UserListItem {
  id: number;
  email: string;
  name: string;
  createdAt: string;
}

interface UserDetail {
  id: number;
  email: string;
  name: string;
  phone: string;
  address: string;
  createdAt: string;
  updatedAt: string;
}

유틸리티 타입 활용

기본 타입을 정의하고 필요에 따라 Pick, Omit으로 파생시키는 방식으로 변경했다.

interface User {
  id: number;
  email: string;
  name: string;
  phone: string;
  address: string;
  createdAt: string;
  updatedAt: string;
}

type UserListItem = Pick<User, 'id' | 'email' | 'name' | 'createdAt'>;
type UserPublicProfile = Omit<User, 'phone' | 'address'>;

PATCH 요청처럼 부분 업데이트가 필요한 경우 Partial을 조합했다.

type UserUpdateRequest = Partial<Pick<User, 'name' | 'phone' | 'address'>>;

결과

타입 정의가 20% 정도 줄었고, User 인터페이스만 수정하면 파생 타입도 자동으로 반영된다. 특히 새로운 필드 추가 시 누락되는 케이스가 사라졌다.

유틸리티 타입은 3.x 이후 지원되던 기능인데 이제서야 제대로 활용하게 됐다. Required, Record 등 다른 타입들도 적용할 곳을 찾아봐야겠다.

TypeScript 유틸리티 타입으로 API 응답 타입 정제하기