In a real-world codebase, interfaces grow. A User type might have 20+ properties covering everything from authentication to UI preferences. But not every part of the codebase needs all of them — a login form cares only about email and password, while an admin panel might need everything except password.
Without the right tools, you end up duplicating type definitions across files. That duplication is a quiet bug incubator. TypeScript's Pick and Omit utility types solve this by letting you derive focused, specialized types directly from a master interface — define each property exactly once and never repeat yourself.
The Problem: Manual Type Duplication
Start with a master User interface:
interface User {
id: number;
name: string;
email: string;
password: string;
role: "admin" | "user";
createdAt: Date;
}
Without utility types, a developer might write separate interfaces for different contexts:
// For the login form
interface LoginCredentials {
email: string;
password: string;
}
// For the public profile
interface PublicProfile {
id: number;
name: string;
role: "admin" | "user";
}
Now there are three places to update whenever the User schema changes. If email gets renamed to emailAddress, you have to remember to update LoginCredentials too. This is exactly the kind of maintenance burden DRY exists to eliminate.
Pick<T, K> — Select Only What You Need
Pick<T, K> creates a new type by selecting a subset of keys K from type T. You name the properties you want, and TypeScript builds the type from the master interface.
type LoginCredentials = Pick<User, "email" | "password">;
// Equivalent to: { email: string; password: string }
type PublicProfile = Pick<User, "id" | "name" | "role">;
// Equivalent to: { id: number; name: string; role: "admin" | "user" }
Both LoginCredentials and PublicProfile are now derived from the master User interface. Rename email to emailAddress in User and TypeScript immediately flags every derived type that referenced the old key — no manual search required.
Use
Pickwhen you need a small, specific subset of a larger type — especially for form inputs, API request payloads, or narrow component props.
Omit<T, K> — Exclude What You Don't Want
Omit<T, K> creates a type with everything from T except the keys listed in K. It's more convenient than Pick when you want most of the properties and only need to drop a few.
type SafeUser = Omit<User, "password">;
// Equivalent to:
// { id: number; name: string; email: string; role: "admin" | "user"; createdAt: Date }
This pattern is common when returning user data from an API — you want the full object minus any sensitive fields.
A practical example
function getUser(id: number): Omit<User, "password" | "createdAt"> {
// returns everything except the sensitive fields
}
Use
Omitwhen your derived type needs most of the parent. It's less verbose than listing every key you do want withPick.
Pick vs Omit — When to Use Which
A quick rule of thumb: if you need fewer than half the properties, reach for Pick. If you only need to exclude one or two, reach for Omit. Both produce the same kind of derived type — the choice is about readability and how many keys you're working with.
| Scenario | Preferred utility |
|---|---|
| Need 2–3 specific fields from a large interface | Pick |
| Need everything except 1–2 sensitive fields | Omit |
| Defining a form input type | Pick |
| Stripping a field before an API response | Omit |
Conclusion
Pick and Omit are not just convenience shortcuts — they're tools for maintaining a single source of truth for your data shapes. By deriving specialized types from a master interface instead of rewriting them, you eliminate redundancy and let TypeScript enforce consistency automatically. This is DRY applied at the type level, and it becomes increasingly valuable as your interfaces grow and your codebase scales.
Top comments (0)