Entry / Feb 13, 2026
TypeScript Utility Types: Partial, Omit, and Pick in Real Code
Why `Partial`, `Omit`, and `Pick` help TypeScript remove duplicated interfaces, keep one source of truth, and make refactors far safer.
There is a point where a clean User interface quietly
turns into three or four almost-identical types.
One for creation. One for updates. One for public data. One for previews. And before long, you are copying the same shape over and over just to add optional fields, hide a couple of properties, or keep only the two values a component actually needs.
That is the duplication problem this video attacks with
three of the most practical TypeScript utility types:
Partial, Omit, and Pick.
The real problem is not typing faster
At first, duplicated interfaces do not look dangerous.
They even feel explicit.
But once the base model changes, every copied type becomes a maintenance risk.
That usually means:
- fields drift out of sync
- refactors miss one version of the contract
- autocomplete becomes less trustworthy
- small changes turn into repetitive edits
This is why utility types matter.
They are not just shortcuts.
They let you keep one source of truth and derive the variants you actually need.
Partial<T> is great for update payloads
The first example in the video is the classic update DTO.
You start with something like this:
interface User {
id: string;
name: string;
email: string;
avatar: string;
}
Then you need to update only some fields, so it is tempting to create another interface by hand.
interface UpdateUser {
name?: string;
email?: string;
avatar?: string;
}
It works, but now the contract is duplicated.
Partial<User> gives you the same optional-field behavior
without rewriting the shape.
function updateUser(id: string, changes: Partial<User>) {
// ...
}
That matters because TypeScript is not guessing anymore. It
knows this update payload is a subset of User.
If the base type changes, the update type stays aligned.
This is one of the clearest examples of compiler-assisted maintenance: you change one model and the derived contract updates with it.
Partial is powerful, but it is shallow
This is one useful nuance to expand beyond the video.
Partial<T> only makes the top-level properties optional.
It does not recursively make nested objects optional.
interface User {
name: string;
settings: {
theme: string;
locale: string;
};
}
type UserPatch = Partial<User>;
In UserPatch, settings is optional, but if you provide
it, TypeScript still expects the full nested object.
That is often the right behavior. It keeps patch payloads honest.
But if your API supports deep partial updates, you may need
a separate domain type or a carefully designed DeepPartial
helper instead of assuming built-in Partial solves every
case.
Omit<T, K> defines what should not cross the boundary
The next example removes fields like id and createdAt
from a derived type.
That is where Omit becomes more than convenience.
interface User {
id: string;
name: string;
email: string;
createdAt: Date;
}
type UserProfile = Omit<User, "id" | "createdAt">;
Now the public or editable shape can stay tied to User
without exposing properties that should not be assigned by
callers.
This is especially useful at API boundaries.
You can model the difference between:
- what the database stores
- what the client is allowed to send
- what the UI is allowed to display
All while keeping the original model as the source of truth.
Pick<T, K> is often the safer public contract
The video closes with Pick, using a lightweight preview
shape such as name and avatar.
type UserPreview = Pick<User, "name" | "avatar">;
This is one of the cleanest ways to express intent in TypeScript.
The type is not “almost a user.”
It is exactly the subset the UI or function needs.
That gives you:
- smaller and more explicit contracts
- better autocomplete for consumers
- fewer accidental dependencies on unrelated fields
- easier reuse across cards, lists, and preview components
In larger systems, Pick is often safer than Omit for
public-facing types.
Why? Because Pick is a whitelist.
If the base User type gains a new sensitive field later,
Pick<User, "name" | "avatar"> does not expose it by
accident. An Omit-based public type might.
These utilities work because TypeScript can transform types
The deeper idea behind the video is that utility types are not random built-ins.
They are examples of mapped types: ways to build one type from another instead of restating the whole contract by hand.
That is why they scale well.
You are not maintaining several separate truths. You are encoding a relationship once and letting TypeScript preserve it.
This is the same design instinct behind many other built-in
helpers like Readonly, Required, and Record.
The compiler becomes more useful when your types describe how shapes relate, not just what one isolated object looks like.
Utility types do not replace domain modeling
There is also an important limit here.
Not every derived type should come from Partial, Omit,
or Pick.
Sometimes a separate type really is the correct abstraction.
For example:
- validation rules may differ from the database model
- a write payload may need fewer fields and different names
- a public response may need computed values, not just hidden fields
That is the maturity line.
Use utility types when they preserve meaning and remove duplication. Write explicit domain types when the contract is genuinely different.
The maintainability win is bigger than fewer lines
The video frames utility types as a way to save code, and that is true.
But the bigger payoff is that they make refactors safer.
When your User model evolves, derived types based on
Partial, Omit, and Pick evolve with it. Autocomplete
stays accurate. Broken assumptions show up earlier. Repeated
manual updates disappear.
That is why these helpers feel so practical.
They do not make TypeScript clever.
They make your system more coherent.
The takeaway
Partial, Omit, and Pick are useful because they stop
you from rewriting the same intent in several places.
They help you express three common relationships clearly:
- an update is a partial version of a model
- a public shape omits fields that should not leak
- a preview picks only the fields a consumer needs
That is not just cleaner syntax.
It is better design.
And once you start treating your base types as a source of truth instead of a template to copy, TypeScript starts doing far more of the maintenance work for you.
