Suggest an editImprove this articleRefine the answer for “Utility type pick in TypeScript”. Your changes go to moderation before they’re published.Approval requiredContentWhat you’re changing🇺🇸EN🇺🇦UAPreviewTitle (EN)Short answer (EN)**Pick<T, K>** selects only the specified keys from T and builds a new type with exactly those fields. ```ts interface User { id: number; name: string; email: string; } type UserPreview = Pick<User, 'id' | 'name'>; // Result: { id: number; name: string } ``` **Key point:** Pick is compile-time only. The actual JavaScript object is not modified, so runtime filtering requires a manual projection.Shown above the full answer for quick recall.Answer (EN)Image**Pick<T, K>** constructs a new type by selecting only the keys you name from T, keeping their original types and dropping everything else. ## Theory ### TL;DR - Think of it like ordering from a menu: you get exactly the dishes you picked, with full recipes intact, nothing extra. - `Pick<User, 'id' | 'name'>` gives you `{ id: number; name: string }` — `email` and the rest are gone. - Keys must exist in T or TypeScript errors at compile time. No runtime filtering, type-check only. - Use Pick for 1-5 related props. For many exclusions, reach for `Omit` instead. ### Quick example ```ts interface User { id: number; name: string; age: number; email: string; } // Picks only 'id' and 'name' — age and email are gone type UserPreview = Pick<User, 'id' | 'name'>; const preview: UserPreview = { id: 1, name: 'Alice' }; // OK const invalid: UserPreview = { id: 1, name: 'Alice', age: 30 }; // Error ``` `UserPreview` only knows about `id` and `name`. Passing `age` is a compile-time error, not a runtime one. ### Key difference Pick creates a **shallow subset**. It copies exact types from T without recursing into nested objects. If T has `{ address: { street: string } }`, then `Pick<T, 'address'>` keeps the whole nested `address` object intact — it just drops other top-level keys. You cannot trim nested fields with a single Pick call. ### When to use - **API response subset**: expose only safe public fields from a full entity (for example, drop `passwordHash` before sending data to the client). - **React component props**: when a component needs 2-4 fields from a larger domain type, Pick keeps the props in sync with the source type automatically. - **Form inputs**: partial update DTOs where you only accept specific fields. - **Event payloads**: pick specific fields from a request body type. Avoid Pick if you need more than 5-6 keys or need to transform types. A mapped type handles those cases better. ### How TypeScript handles Pick internally Pick is defined as a mapped type: `type Pick<T, K extends keyof T> = { [P in K]: T[P] }`. The compiler iterates through K, looks up each key's type in T via indexed access, and builds a new object type. No runtime code is produced — Pick is erased entirely after type checking. That also means Pick has zero cost at runtime. The compiled JavaScript is identical whether you annotate with `User` or `Pick<User, 'id'>`. ### Common mistakes **Assuming runtime filtering** ```ts const fullUser = { id: 1, name: 'Alice', secret: 'pass123' }; const picked: Pick<User, 'id' | 'name'> = fullUser; // Compiles fine! // But secret is still in the object at runtime ``` Pick does not strip properties from actual objects. It only constrains what TypeScript lets you type-check against. To project at runtime, build the object manually: `const picked = { id: fullUser.id, name: fullUser.name }`. **Using a wide `string` as K** ```ts const key = 'id' as string; type Wrong = Pick<User, typeof key>; // Error: 'string' not assignable to keyof User ``` K must be string literal types. Use `'id' | 'name'` or a `keyof` subset, not the broad `string` type. **Forgetting that optional props stay optional** ```ts interface User { id: number; name?: string; } type Picked = Pick<User, 'name'>; // { name?: string } — still optional ``` If you need `name` required after picking, wrap it: `Required<Pick<User, 'name'>>`. **Nested types need chained indexed access** ```ts interface User { details: { age: number }; } // This gives { details: { age: number } } — not just age type A = Pick<User, 'details'>; // To get only age from details: type B = Pick<User['details'], 'age'>; // { age: number } ``` ### Real-world usage - **React / Next.js**: `Pick<User, 'id' | 'name'>` as list item component props. - **Express / NestJS**: `Pick<User, 'name' | 'email'>` for update DTOs in controllers. - **Redux Toolkit**: `Pick<Action, 'type' | 'payload'>` for typed action creators. - **tRPC**: procedure inputs typed as `Pick<Entity, PublicKeys>`. One thing I see teams miss consistently: they annotate the return type with Pick but forget to project the object at runtime. Sensitive fields end up in the response even though the TypeScript type looks correct. ### Follow-up questions **Q:** What does `Pick<User, keyof User>` produce? **A:** The same type as `User`. Selecting all keys gives back the original shape. **Q:** Can you Pick from a union type? **A:** Yes, `Pick<User | Admin, 'id' | 'name'>` distributes across the union. The result includes the common keys from both members. **Q:** What is `Pick<T, never>`? **A:** An empty object type `{}`. Selecting no keys produces a type that only accepts an empty object. **Q:** (Senior) Implement Pick from scratch. **A:** `type MyPick<T, K extends keyof T> = { [P in K]: T[P] }`. The constraint `K extends keyof T` is what makes non-existent keys a compile-time error. **Q:** How does Pick differ from writing the type manually? **A:** The resulting structures are identical, but Pick stays in sync automatically. If you add a field to `User` and it matches a picked key, every derived type updates without touching it manually. ## Examples ### Basic: exposing public fields from a User ```ts interface User { id: number; name: string; email: string; passwordHash: string; // never expose this isAdmin: boolean; } type PublicProfile = Pick<User, 'id' | 'name' | 'email'>; function getPublicProfile(user: User): PublicProfile { // Manual projection — Pick constrains the type, not the runtime object return { id: user.id, name: user.name, email: user.email, }; } ``` `passwordHash` and `isAdmin` are excluded from the return type. The function must project explicitly — TypeScript does not strip them automatically. ### Intermediate: React component props from a domain model ```ts interface User { id: number; name: string; email: string; role: 'user' | 'admin'; createdAt: Date; } type UserCardProps = Pick<User, 'id' | 'name' | 'role'>; const UserCard = ({ id, name, role }: UserCardProps) => ( <div> {id} — {name} ({role}) </div> ); // Only the picked props are required <UserCard id={1} name='Bob' role='admin' />; ``` `UserCardProps` stays in sync with `User`. If you rename `role` in the interface, TypeScript flags every Pick referencing it. That is the main benefit over writing props by hand.For the reviewerNote to the moderator (optional)Visible only to the moderator. Helps review go faster.