TypeScript 유틸리티 타입 Pick<T, K> – 객체 타입에서 필요한 것만 뽑아 쓰기

2025. 12. 13. 15:17·FrontEnd/TypeScript

코드 짜다 보면 이런 생각이 한 번씩 든다.

  • "User 타입 전체는 너무 크고"
  • "지금 이 화면에서는 name이랑 email만 있으면 되는데"
  • "타입을 새로 만들자니 귀찮고, any 쓰자니 찝찝하고"

이럴 때 쓰는 게 Pick<T, K>다.


1. Pick<T, K>를 한 줄로 설명하면

Pick<T, K>는

어떤 객체 타입 T에서
필요한 속성 이름 K만 골라서
새로운 타입을 만드는 도구다.

 

생각보다 단순하다.


2. 기본 사용법부터 보기

먼저 예제로 감 잡고 나중에 정의를 보자.

type User = {
  id: number
  name: string
  email: string
  isAdmin: boolean
}

// 프로필 화면에서 필요한 정보만
type UserProfile = Pick<User, "id" | "name">

const profile: UserProfile = {
  id: 1,
  name: "홍길동"
  // email, isAdmin은 없어도 된다
}

여기서 알 수 있는 점

  • User는 그대로 두고
  • UserProfile은 User 안에서 "id" | "name"만 골라서 만든 타입
  • User에 필드가 추가되면
    • UserProfile도 타입 체크를 같이 받는다
    • "iddd"처럼 오타로 적으면 컴파일 단계에서 바로 에러가 난다

3. Pick<T, K>가 실제로 뭔지 살짝만 들여다보기

참고용으로 공식 정의는 이런 모양이다.

type Pick<T, K extends keyof T> = {
  [P in K]: T[P]
}

이걸 풀어서 보면

  • T에 있는 key들 중에서
  • K에 해당하는 key만 돌면서
  • T에서 그 key의 타입을 그대로 가져온다

여기서 중요한 포인트는 두 가지다.

  • K는 반드시 T 안에 존재하는 키여야 한다.
    "age"를 골라 쓰려면 User 안에 진짜 age가 있어야 한다.
  • 이건 런타임 동작이 아니라 타입 시스템에서만 도는 논리다.
    실제로 JS 객체에서 필드가 삭제되거나 하지는 않는다.

4. 실무에서 언제 쓰면 좋은지

4-1. 리스트용 요약 데이터 만들 때

목록 화면은 보통 전체 데이터가 다 필요 없다.

type Product = {
  id: string
  name: string
  price: number
  description: string
  createdAt: string
}

// 리스트 카드에 필요한 필드만
type ProductListItem = Pick<Product, "id" | "name" | "price">

이렇게 해 두면

  • 리스트 컴포넌트는 Product 전체를 요구하지 않고
  • 진짜로 사용하는 필드만 Props로 받게 된다.
type ProductCardProps = {
  product: ProductListItem
}

4-2. 폼용 타입 분리할 때

회원가입, 설정, 수정 같은 폼은 DB 전체 스키마랑 1:1로 맞출 필요가 없다.

type User = {
  id: number
  name: string
  email: string
  password: string
  isAdmin: boolean
}

// 가입 폼에 실제로 입력 받는 값만
type SignUpFormValues = Pick<User, "name" | "email" | "password">

장점은 이런 느낌이다.

  • 나중에 User에 필드가 늘어나도
    폼에 불필요한 필드가 갑자기 끼어들지 않는다.
  • 폼 검증 스키마(Zod 등)와 타입을 맞추기도 편하다.

4-3. API 응답에서 필요한 필드만 흘려보낼 때

백엔드에서 내려오는 타입이 꽤 크고 복잡한 경우,
레이어별로 필요한 범위만 줄여서 쓰는 데도 잘 맞는다.

// API에서 내려온 전체 타입
type UserDTO = {
  id: number
  name: string
  email: string
  phone: string
  address: string
  createdAt: string
  // ...
}

// 헤더 프로필 드롭다운에 필요한 정보만
type HeaderUser = Pick<UserDTO, "id" | "name" | "email">

function HeaderUserMenu(props: { user: HeaderUser }) {
  // 여기서는 name, email 정도만 쓰는 상황
}

의도를 타입으로 표현하는 느낌이라고 보면 된다.

이 컴포넌트는 User 데이터 중에 “이 정도 정보만 관심 있다”

 

라는 걸 타입 자체에 박아두는 것


5. Pick을 막 쓰기 전에 생각해 볼 것

유틸리티 타입은 편해서 막 쓰기 좋은데,
너무 막 쓰면 오히려 읽기 힘들어지는 경우도 생긴다.

5-1. "이제 거의 다른 타입인데?" 싶은 경우

원본 타입과 의미가 너무 달라지면
아예 새 타입 이름을 정해서 만드는 편이 더 낫다.

// 애매한 예
type UserListRow = Pick<User, "id" | "name" | "createdAt">

// 차라리
type UserListRow = {
  id: number
  name: string
  joinedAt: string
}

이미 도메인에서 완전히 다른 의미라면
Pick으로 끌어다 쓰는 대신 타입을 분리하는 것도 고려할 만하다.

5-2. 중첩 Pick / 중첩 유틸리티 남발

type Something = Partial<Pick<User, "name" | "email">>

이 정도는 괜찮은데,
실무에서 가끔 이런 것도 본다.

type X = Partial<
  Pick<
    SomeBigType,
    "fieldA" | "fieldB" | "fieldC" | "fieldD"
  >
>

이게 한두 번이면 괜찮지만,
여러 군데에서 이렇게 쓰이면 읽는 사람이 해석하기가 점점 힘들어진다.

그럴 때는

  • 중간에 한 번 타입을 이름 붙여서 끊거나
  • 아예 도메인에 맞는 새 타입을 선언하는 편이 나을 때도 있다.

5-3. 런타임에서 필드가 실제로 제거되는 건 아니다

Pick은 타입 단계에서만 작동한다.

type UserProfile = Pick<User, "id" | "name">

declare const user: User
declare const profile: UserProfile

이렇게 되어 있어도 런타임에서는
user 객체가 그대로 돌아다닌다.

  • 네트워크로 보낼 때
  • 로깅할 때

실제로 필드를 빼고 싶다면
타입이 아니라 데이터 처리 로직이 별도로 필요하다.


6. 정리 – Pick을 언제 떠올리면 되는가

짧게 정리하면 이렇게 쓰면 좋다.

  • 기존 타입에서 일부 필드만 안전하게 써야 할 때
  • 컴포넌트가 정말로 사용하는 필드만 Props로 받고 싶을 때
  • 폼, 목록, 카드 등에서 요약 정보 타입이 필요할 때
  • 원본 타입이 바뀌면 관련 타입도 자동으로 같이 체크 받고 싶을 때

반대로 이런 경우에는 한 번 더 생각해 보면 좋다.

  • 의미가 거의 다른 타입인데 억지로 Pick으로 이어 붙이고 있지는 않은지
  • 유틸리티 타입이 너무 중첩되어서
    읽는 사람이 해석하기 어렵지 않은지
저작자표시 비영리 변경금지 (새창열림)

'FrontEnd > TypeScript' 카테고리의 다른 글

TypeScript as const 이게 뭘까  (0) 2025.12.18
TypeScript 유틸리티 타입 Partial<T> – 부분만 채워도 되는 타입 만들기  (1) 2025.12.14
TypeScript 유틸리티 타입 Omit<T, K> – 필요 없는 필드만 쏙 빼고 쓰기  (0) 2025.12.14
타입연산자 typeof, keyof, keyof typeof 패턴 정리  (0) 2025.12.14
setTimeout() 반환값 정리 – 브라우저 vs Node에서 뭐가 다른지  (0) 2024.11.24
'FrontEnd/TypeScript' 카테고리의 다른 글
  • TypeScript 유틸리티 타입 Partial<T> – 부분만 채워도 되는 타입 만들기
  • TypeScript 유틸리티 타입 Omit<T, K> – 필요 없는 필드만 쏙 빼고 쓰기
  • 타입연산자 typeof, keyof, keyof typeof 패턴 정리
  • setTimeout() 반환값 정리 – 브라우저 vs Node에서 뭐가 다른지
프론트엔드 개발자 jbeat
프론트엔드 개발자 jbeat
프론트엔드 개발자 블로그인데 일상도 쪼그으믐
  • 프론트엔드 개발자 jbeat
    jbeat 님의 블로그
    프론트엔드 개발자 jbeat
  • 전체
    오늘
    어제
    • 분류 전체보기 (44)
      • FrontEnd (43)
        • TypeScript (6)
        • JavaScript (18)
        • Next.js (3)
        • React (1)
        • Testing (2)
        • Third Party (1)
        • web (10)
        • Tooling (1)
        • coding test (0)
        • A.I (1)
      • 일상 (1)
        • wedding (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 인기 글

  • 태그

    Android
    CrossOrigin
    Next.js
    타입스크립트
    WebSocket
    playwright
    Utility
    컬렉션
    고차함수
    TypeScript
    pick
    코테
    omit
    CRDT
    yjs
    preconnect
    주니어
    배열
    이터러블
    javascript
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.5
프론트엔드 개발자 jbeat
TypeScript 유틸리티 타입 Pick<T, K> – 객체 타입에서 필요한 것만 뽑아 쓰기
상단으로

티스토리툴바