Pick<Type, Keys>
Constructs a type from Type keeping only the named properties.
type Pick<Type, Keys extends keyof Type> = { [Property in Keys]: Type[Property] }- Added in TypeScript 2.1
Parameters
| Parameter | Type | Description |
|---|---|---|
$Type | any type | The source type to project from. |
$Keys | keyof Type (a key or union of keys of Type) | The property keys to keep. Constrained to `keyof Type`, so a key that does not exist on Type is a compile error. |
Return value
An object type containing only the properties named in KeysA mapped type over Keys where each property keeps its original type from Type, including optionality and readonly modifiers.
Errors
A key in Keys that is not assignable to `keyof Type` fails the constraint: "Type '"x"' does not satisfy the constraint 'keyof Type'".
Changelog
- PHP 3.5`Omit` was added to the standard library as `Pick<T, Exclude<keyof T, K>>`, making the two the standard subtractive/additive pair.
Pick builds a new object type from an existing one by keeping the properties you name. Property types, optionality and readonly modifiers all carry over untouched.
When to reach for it
- Projections. A list endpoint returns
Pick<User, "id" | "name">while the detail endpoint returns the wholeUser. The two stay in sync automatically. - Narrow function parameters. A function that only reads
idandstatusshould say so:function summarise(order: Pick<Order, "id" | "status">). Callers can pass a fullOrder, and the signature documents exactly what is touched. - Component props. Forward a subset of a model's fields without redeclaring their types.
Pick versus Omit
They are two views of the same operation — Omit is literally defined as Pick<Type, Exclude<keyof Type, Keys>>. Choose Pick when the kept set is small and stable, and Omit when the removed set is. The practical difference is what happens when the source type grows a field: a Pick ignores it, an Omit silently includes it.
What trips people up
Keys is constrained to keyof Type, so typos are caught — unlike Omit. And Pick is not deep: picking an object-valued property gives you the whole nested object.
Example
When to use it
- Define a list-view DTO as a projection of the full model type.
- Declare a function parameter as only the fields the function actually reads.
- Build a form's value type from the subset of model fields the form edits.
Frequently asked questions
How do I create a type with only some properties of an interface?
Use `Pick<T, "a" | "b">` — it maps over the named keys and copies each property's type, optionality and readonly modifier from the source.
What is the difference between Pick and Omit?
`Pick` names the properties to keep, `Omit` names the ones to remove — and `Omit` is literally implemented as `Pick<T, Exclude<keyof T, K>>`. The practical difference is that `Pick` is constrained to real keys of `T` while `Omit` accepts any key.
Does Pick keep optional and readonly modifiers?
Yes. Homomorphic mapped types like `Pick` preserve the `?` and `readonly` modifiers of each property they copy, so an optional field stays optional.
More examples
A parameter that declares exactly what it reads
Prints `ord_9 [shipped]` then `ord_10 [pending]`. Both calls type-check: the full `Order` is assignable to the picked type because it has at least those properties, and the two-key literal is assignable because it has exactly them. Tests can now construct the tiny object instead of a whole fixture.
interface Order {
id: string;
customerId: string;
status: "pending" | "shipped" | "cancelled";
lineItems: { sku: string; qty: number }[];
internalNotes: string;
}
// The signature promises this function never sees notes or line items.
function badge(order: Pick<Order, "id" | "status">): string {
return `${order.id} [${order.status}]`;
}
const full: Order = {
id: "ord_9",
customerId: "cus_1",
status: "shipped",
lineItems: [{ sku: "A1", qty: 2 }],
internalNotes: "call before delivery",
};
console.log(badge(full)); // a full Order is accepted
console.log(badge({ id: "ord_10", status: "pending" })); // so is the minimumPick and Omit over the same interface
The two logs show the halves of the same record: `{ email: '[email protected]', passwordHash: '9f3c' }` and `{ id: 1, name: 'Ada', email: '[email protected]' }`. Note that `Omit<User, "passwordHash">` and the rest-destructuring line up exactly — that pairing is why rest destructuring is the idiomatic runtime companion to `Omit`.
interface User {
id: number;
name: string;
email: string;
passwordHash: string;
}
type Credentials = Pick<User, "email" | "passwordHash">;
type SafeUser = Omit<User, "passwordHash">;
const record: User = {
id: 1,
name: "Ada",
email: "[email protected]",
passwordHash: "9f3c",
};
const creds: Credentials = {
email: record.email,
passwordHash: record.passwordHash,
};
const { passwordHash, ...safe } = record;
const forClient: SafeUser = safe;
console.log(creds);
console.log(forClient);
Discussion