TypeScript comes with a “Swiss Army Knife” of predefined types called Utility Types. They are Generics that take a type and return a modified version.
Partial<T> (Everything optional)
Imagine we have a complete user, but for an update (PATCH), we only send the fields that changed.
interface User {
id: number;
name: string;
email: string;
}
function updateUser(id: number, changes: Partial<User>) {
// 'changes' is now as if all props had '?'
// { id?: number; name?: string; email?: string; }
...
}
updateUser(1, { name: "Alice" }); // ✅ Validinterface User {
id: number;
name: string;
email: string;
}
function updateUser(id: number, changes: Partial<User>) {
// 'changes' is now as if all props had '?'
// { id?: number; name?: string; email?: string; }
...
}
updateUser(1, { name: "Alice" }); // ✅ ValidRequired<T> (Everything required)
The opposite of Partial. Removes all ? from an interface.
Pick<T, Keys> (Pick what you want)
Sometimes we have a huge interface and only need a couple of fields for a small component.
interface Product {
id: number;
name: string;
price: number;
description: string;
stock: number;
...
}
// We create a new type only with name and price
type ProductLabel = Pick<Product, "name" | "price">;
// { name: string; price: number; }interface Product {
id: number;
name: string;
price: number;
description: string;
stock: number;
...
}
// We create a new type only with name and price
type ProductLabel = Pick<Product, "name" | "price">;
// { name: string; price: number; }Omit<T, Keys> (Remove what you DON’T want)
The opposite of Pick. Removes specific fields. Very useful to remove sensitive or unnecessary data.
// A User without the password
type PublicUser = Omit<User, "password">;// A User without the password
type PublicUser = Omit<User, "password">;Record<Keys, Type> (Dictionaries)
This one is a bit special. It serves to create objects where we don’t know the name of the properties, but we know what values they will have.
Think of a Phone Book:
- The Keys are names (Strings).
- The Values (Type) are numbers (Numbers).
We don’t know if you will save “Pepe” or “Maria”, but we know the structure will always be Name -> Number.
// A normal object requires knowing the keys beforehand
// interface Agenda { pepe: number } // ❌ Impractical
// With Record:
const agenda: Record<string, number> = {};
agenda["Pepe"] = 123456;
agenda["Maria"] = 987654;// A normal object requires knowing the keys beforehand
// interface Agenda { pepe: number } // ❌ Impractical
// With Record:
const agenda: Record<string, number> = {};
agenda["Pepe"] = 123456;
agenda["Maria"] = 987654;Hands on!
- Create
TodoUpdateusingPartialofTodo. - Create
TodoPreviewusingPickofTodo(onlytitleandcompleted). - Create
TodoDictionarywhich is aRecordwhere the key isstringand the value isTodo.