Lesson 13 of 25
Utility Types, Part 1: Partial, Required, Readonly, Pick, Omit
Five built-in generic types that transform an existing type instead of redeclaring it by hand — the most commonly reached-for tool in real TypeScript code.
A huge amount of real TypeScript work is deriving one type from another, slightly differently shaped, type — "this, but every field optional," "this, but only three of its fields." TypeScript ships a set of generic types built exactly for this, so you don't hand-write the derived shape every time.
The problem: types that repeat each other
interface User {
id: string;
name: string;
email: string;
age: number;
}
// Updating a user — every field is optional, since you might
// only change one at a time. Without a utility type, you'd write:
interface UserUpdate {
id?: string;
name?: string;
email?: string;
age?: number;
}UserUpdate is entirely derivable from User — every property, just made
optional. Writing it out by hand means the two types drift the moment
someone adds a field to User and forgets UserUpdate. Utility types solve
this by deriving the second type mechanically from the first.
Partial<T>
Makes every property of T optional:
function updateUser(id: string, changes: Partial<User>) {
// changes might contain any subset of User's fields
}
updateUser("1", { name: "New Name" }); // fine — everything else omitted
updateUser("1", {}); // also fine — an empty updateAdd a field to User later, and Partial<User> picks it up automatically,
still optional, with zero extra code.
Required<T>
The opposite of Partial — strips ? from every property, making all of
them mandatory:
interface Settings {
theme?: string;
fontSize?: number;
}
function applySettings(settings: Required<Settings>) {
// theme and fontSize are both guaranteed present here
}
applySettings({ theme: "dark", fontSize: 14 }); // fine
applySettings({ theme: "dark" });
// Property 'fontSize' is missing.Useful for a function that needs every optional field filled in — after merging user settings with defaults, for instance.
Readonly<T>
Adds readonly to every property of T, without writing it on each one by
hand:
const config: Readonly<Settings> = { theme: "dark", fontSize: 14 };
config.theme = "light";
// Cannot assign to 'theme' because it is a read-only property.Same compile-time-only behaviour as readonly on a single property from
earlier in this track — this utility type just saves repeating it across
every field.
Pick<T, Keys>
Builds a new type containing only the listed properties of T:
type UserPreview = Pick<User, "id" | "name">;
// { id: string; name: string }
const preview: UserPreview = { id: "1", name: "Amara" };The second argument is a union of string literal keys — each one must
actually exist on T, or it's a compile error, which is exactly the safety
net that makes this better than redeclaring { id: string; name: string }
by hand: a typo in the key name is caught immediately.
Omit<T, Keys>
The inverse of Pick — keeps everything except the listed properties:
type PublicUser = Omit<User, "email">;
// { id: string; name: string; age: number }
const publicUser: PublicUser = { id: "1", name: "Amara", age: 29 };Omit is usually more convenient than Pick when you want "almost
everything" — listing the one or two fields to exclude is shorter than
listing every field you want to keep.
How Partial and friends are actually defined
Worth a preview, even though the mechanism (a mapped type) is covered in
full later in this track — Partial<T> is not a special compiler
built-in, just an ordinary generic type defined in TypeScript's standard
library:
type Partial<T> = {
[K in keyof T]?: T[K];
};Nothing here is off-limits to you — once mapped types are covered, you'll be able to write your own version of any of these five from scratch.
Try it yourself
What to remember
Partial<T>makes every property optional;Required<T>makes every property mandatory.Readonly<T>marks every property readonly, at compile time only — the same guarantee as a single readonly property, applied to all of them.Pick<T, Keys>keeps only listed properties;Omit<T, Keys>keeps everything except the listed ones.- All five derive a new type from an existing one mechanically, so the derived type stays correct as the source type changes.
Check yourself
4 questions · pass 3/4 to unlock Utility Types, Part 2: Record, Exclude, Extract, and the Function Ones
1.Given
interface User { name: string; age: number }, what doesPartial<User>produce?2.What is
Pick<User, "name">for the User interface above?3.What is
Omit<User, "age">?4.What does Readonly<T> change that plain readonly on individual properties doesn't?
4 left to answer