TypeScript 실무 효율을 200% 높이는 유틸리티 타입 핵심 정리

🎯 타겟 독자: TypeScript를 사용하지만 매번 interface를 새로 만드는 것이 귀찮은 프론트엔드/백엔드 개발자, 중복 코드를 줄이고 타입 안정성을 높이고 싶은 실무자.


📝 요약: TypeScript의 Utility Types는 기존 타입을 변형하여 새로운 타입을 만들어내는 강력한 기능입니다. 이 글에서는 실무에서 가장 빈번하게 사용되는 Pick, Omit, Partial, Record의 정확한 사용법과, 이를 조합하여 API 요청/응답 타입을 효율적으로 관리하는 패턴을 소개합니다.

타입스크립트 유틸리티 타입

1. 왜 유틸리티 타입을 써야 하나요?

개발을 하다 보면 하나의 User 인터페이스가 상황에 따라 조금씩 다르게 필요할 때가 있습니다.

  • 회원가입 시: ID와 생성일은 필요 없음 (아직 안 만들어졌으니까)
  • 프로필 수정 시: 이메일은 수정 불가 (Readonly 필요)
  • 목록 조회 시: 비밀번호 필드는 제외 (보안상)

이때마다 UserSignupDto, UserUpdateDto를 일일이 새로 만드는 것은 중복이며 유지보수의 악몽입니다. 유틸리티 타입을 쓰면 원본 타입 하나로 모든 파생 타입을 만들어낼 수 있습니다.

2. 필수 유틸리티 타입 Best 4

① Pick <Type, Keys> : 쏙쏙 골라내기

거대한 타입에서 필요한 몇 가지 속성만 선택해서 새로운 타입을 만듭니다.

interface User { id: number; email: string; username: string; admin: boolean; } // 로그인 화면에는 이메일과 비밀번호만 필요함 type UserLogin = Pick<User, "email" | "password">; // 결과: { email: string; password: string; }

② Omit <Type, Keys> : 콕 집어 빼기

Pick의 반대입니다. 특정 속성만 제거하고 나머지는 다 가져옵니다.

// 클라이언트에 내려줄 때 민감한 정보 제외 type UserResponse = Omit<User, "password" | "admin">; // 결과: { id: number; email: string; username: string; }

③ Partial <Type> : 모두 선택 사항으로

모든 속성을 Optional (?) 상태로 만듭니다. 주로 PATCH(수정) API 요청 타입에 쓰입니다.

// 일부 정보만 수정할 수 있으므로 모든 필드가 선택 사항 type UpdateUserDto = Partial<User>; // 결과: { id?: number; email?: string; ... }

④ Record <Keys, Type> : 객체 사전 만들기

키(Key)와 값(Value)의 타입이 고정된 객체(Dictionary/Map)를 정의할 때 가장 깔끔합니다.

type Role = "admin" | "user" | "guest"; // 각 역할별 권한 페이지 목록 정의 const permissions: Record<Role, string[]> = { admin: ["settings", "users"], user: ["mypage"], guest: ["login"] // "manager" 같은 엉뚱한 키를 넣으면 에러 발생! };

3. 실무 응용 패턴 (조합해서 쓰기)

유틸리티 타입은 중첩해서 쓸 때 진가를 발휘합니다.

예를 들어, "회원 정보를 수정하되, ID는 수정 못 하고, 나머지 필드는 선택적으로 보내도 된다"는 요구사항을 코드로 표현하면 다음과 같습니다.

// 1. Omit으로 'id' 제거 (수정 불가 필드 제거) // 2. Partial로 나머지 필드를 모두 Optional로 변경 type UserUpdatePayload = Partial<Omit<User, "id">>; /* 결과 타입: { email?: string; username?: string; admin?: boolean; // id는 아예 존재하지 않음 } */

4. 결론

TypeScript의 유틸리티 타입을 잘 활용하면 "단 하나의 진실된 타입(Single Source of Truth)"을 유지할 수 있습니다.

원본 인터페이스인 User가 바뀌면, Pick이나 Omit으로 파생된 DTO들도 자동으로 같이 바뀝니다. 코드를 복사-붙여넣기 하지 마세요. 타입에게 계산을 맡기세요.

이 블로그의 인기 게시물

Docker 컨테이너 'Connection Refused' (Errno 111) 오류 해결 가이드

Redis 캐싱 전략 완벽 가이드: Look Aside부터 Write Back까지 (DB 부하 줄이기)

브라우저 렌더링 원리: Reflow와 Repaint 최적화 가이드 (CRP 심층 분석)