Skip to content
Laviyx Learn

Try

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.

Advanced9 min readUpdated
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:

TypeScript
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);
Output
admin

Partial 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:

TypeScript
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);
Output
{ id: 2, name: 'Ravi', email: 'ravi.k@example.com' }
+91 98765 43210

Readonly#

Readonly<T> makes every property readonly:

TypeScript
interface Config {
  apiUrl: string;
  retries: number;
}
const config: Readonly<Config> = { apiUrl: "https://api.example.com", retries: 3 };
config.retries = 5;
Compiler error
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:

TypeScript
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" }));
Output
{ 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):

TypeScript
type Role = "admin" | "member" | "guest";
const permissions: Record<Role, string[]> = {
  admin: ["read", "write", "delete"],
  member: ["read", "write"],
  guest: ["read"],
};
console.log(permissions.member);
Output
[ 'read', 'write' ]

Working with unions: Exclude, Extract, NonNullable#

These operate on union types:

TypeScript
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);
Output
review archived Asha

Function types: ReturnType, Parameters, Awaited#

TypeScript
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);
Output
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#

UtilityResult
Partial<T>All properties optional
Required<T>All properties required
Readonly<T>All properties readonly
Pick<T, K>Only properties K
Omit<T, K>All properties except K
Record<K, V>Object with keys K and values V
Exclude<U, X>Union U without members assignable to X
Extract<U, X>Union members of U assignable to X
NonNullable<T>T without null and undefined
ReturnType<F>Return type of function type F
Parameters<F>Parameter types of F as a tuple
Awaited<T>The value a promise resolves to

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
TypeScript
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);
Output
{ id: 'p1', name: 'Pen', price: 25 } 90

Key takeaway#

Finished this lesson?