TypeScript course menu
TypeScript Utility Types: Partial, Required, Pick, Omit, Record, ReturnType and More
Learn TypeScript's built-in utility types with practical examples: Partial, Required, Readonly, Pick, Omit, Record, Exclude, Extract, NonNullable, ReturnType, Parameters, Awaited, and how to combine them for update payloads, forms and API types.
On this page
TypeScript includes utility types: generic types that transform other types. Instead of writing a new type for every variation (a user without an id, a user where every field is optional), you derive it from one main type, so everything stays in sync.
All examples use this type:
interface User {
id: number;
name: string;
email: string;
phone?: string;
role: "admin" | "member";
}
const asha: User = { id: 1, name: "Asha", email: "asha@example.com", role: "admin" };
console.log(asha.role);adminPartial and Required#
Partial<T> makes every property optional; Required<T> makes every property required. Partial is perfect for update payloads, where only changed fields are sent:
interface User {
id: number;
name: string;
email: string;
phone?: string;
}
function updateUser(user: User, changes: Partial<User>): User {
return { ...user, ...changes };
}
const ravi: User = { id: 2, name: "Ravi", email: "ravi@example.com" };
console.log(updateUser(ravi, { email: "ravi.k@example.com" }));
const complete: Required<User> = { ...ravi, phone: "+91 98765 43210" }; // phone is now required
console.log(complete.phone);{ id: 2, name: 'Ravi', email: 'ravi.k@example.com' }
+91 98765 43210Readonly#
Readonly<T> makes every property readonly:
interface Config {
apiUrl: string;
retries: number;
}
const config: Readonly<Config> = { apiUrl: "https://api.example.com", retries: 3 };
config.retries = 5;error TS2540: Cannot assign to 'retries' because it is a read-only property.Pick and Omit#
Pick<T, Keys> keeps only some properties; Omit<T, Keys> removes some:
interface User {
id: number;
name: string;
email: string;
password: string;
role: "admin" | "member";
}
type PublicProfile = Pick<User, "id" | "name">;
type NewUser = Omit<User, "id">; // the server assigns the id
type SafeUser = Omit<User, "password">; // never send the password back
const profile: PublicProfile = { id: 1, name: "Asha" };
const signup: NewUser = { name: "Ravi", email: "ravi@example.com", password: "s3cret!", role: "member" };
function toSafe({ password, ...rest }: User): SafeUser {
return rest;
}
console.log(profile, signup.name);
console.log(toSafe({ id: 3, name: "Meera", email: "m@example.com", password: "x", role: "member" }));{ id: 1, name: 'Asha' } Ravi
{ id: 3, name: 'Meera', email: 'm@example.com', role: 'member' }Utility types can be nested: Partial<Omit<User, "id">> is "any subset of the editable fields".
Record#
Record<Keys, Value> builds an object type from a set of keys (Index Signatures and Record):
type Role = "admin" | "member" | "guest";
const permissions: Record<Role, string[]> = {
admin: ["read", "write", "delete"],
member: ["read", "write"],
guest: ["read"],
};
console.log(permissions.member);[ 'read', 'write' ]Working with unions: Exclude, Extract, NonNullable#
These operate on union types:
type Status = "draft" | "review" | "published" | "archived";
type Visible = Exclude<Status, "draft" | "archived">; // "review" | "published"
type Final = Extract<Status, "published" | "archived">; // "published" | "archived"
type MaybeName = string | null | undefined;
type Name = NonNullable<MaybeName>; // string
const v: Visible = "review";
const f: Final = "archived";
const n: Name = "Asha";
console.log(v, f, n);review archived AshaFunction types: ReturnType, Parameters, Awaited#
async function fetchOrder(id: number, includeItems: boolean) {
return { id, total: 1699, items: includeItems ? ["Pen", "Bag"] : [] };
}
type FetchArgs = Parameters<typeof fetchOrder>; // [id: number, includeItems: boolean]
type OrderPromise = ReturnType<typeof fetchOrder>; // Promise<{ id: number; total: number; items: string[] }>
type Order = Awaited<OrderPromise>; // { id: number; total: number; items: string[] }
const args: FetchArgs = [7, true];
const order: Order = await fetchOrder(...args);
console.log(order.total, order.items);1699 [ 'Pen', 'Bag' ]These let you reuse the types that functions already produce, such as the return type of a library function that does not export its types.
Quick reference#
Utility types are written with features you will learn next: mapped types and conditional types.
Practice#
Practice exercise
Given an interface Product { id: string; name: string; price: number; stock: number; description?: string }, create types ProductInput (everything except id), ProductUpdate (any subset of ProductInput), and ProductSummary (only id, name and price). Write applyUpdate(p: Product, u: ProductUpdate): Product and test it.
Show solution
interface Product {
id: string;
name: string;
price: number;
stock: number;
description?: string;
}
type ProductInput = Omit<Product, "id">;
type ProductUpdate = Partial<ProductInput>;
type ProductSummary = Pick<Product, "id" | "name" | "price">;
function applyUpdate(p: Product, u: ProductUpdate): Product {
return { ...p, ...u };
}
const pen: Product = { id: "p1", name: "Pen", price: 20, stock: 100 };
const updated = applyUpdate(pen, { price: 25, stock: 90 });
const summary: ProductSummary = { id: updated.id, name: updated.name, price: updated.price };
console.log(summary, updated.stock);{ id: 'p1', name: 'Pen', price: 25 } 90Key takeaway#
Finished this lesson?