TypeScript Utility Types

TypeScript ships a set of built-in utility types that transform existing types into new ones without repeating yourself.

#Jobseeker

Find matching jobs & Auto apply with AI

Hyring
Jobseeker using Hyring to search, apply, and prepare with AI

Why Utility Types Matter

As an application grows, you often need slight variations of the same shape: a version where every field is optional for a form draft, a version with only a few fields for a summary view, or a version where nothing can be mutated. Utility types let you derive these variations from one source type instead of maintaining several near-duplicate interfaces by hand.

The Base Type

interface Product {
  id: number;
  name: string;
  price: number;
  description: string;
}

Partial and Required

Partial<T> makes every property in T optional, which is perfect for update functions where the caller only sends the fields that changed. Required<T> does the opposite, forcing every optional property to become mandatory.

Partial and Required

function updateProduct(id: number, changes: Partial<Product>): void {
  console.log(`Updating product ${id}`, changes);
}

updateProduct(1, { price: 29.99 }); // only price is required here

type FullProduct = Required<Product>;
// every field, including any optional ones, is now mandatory

Pick and Omit

Pick<T, Keys> builds a new type containing only the listed properties, while Omit<T, Keys> builds a new type with every property except the listed ones. Both are ideal for shaping API responses or props objects around a subset of a larger model.

Pick and Omit

type ProductSummary = Pick<Product, "id" | "name">;

const summary: ProductSummary = { id: 1, name: "Desk Lamp" };

type ProductWithoutDescription = Omit<Product, "description">;

const noDesc: ProductWithoutDescription = {
  id: 2,
  name: "Chair",
  price: 89,
};
Note: Pick and Omit are exact opposites: Pick<T, K> keeps only K, and Omit<T, K> keeps everything except K.

Record and Readonly

Record<Keys, ValueType> builds an object type mapping every key in Keys to ValueType, which is useful for lookup tables and dictionaries. Readonly<T> marks every property as readonly, preventing reassignment after the object is created.

Record and Readonly

type Inventory = Record<string, number>;

const stock: Inventory = {
  "desk-lamp": 12,
  chair: 5,
};

const frozenProduct: Readonly<Product> = {
  id: 3,
  name: "Monitor",
  price: 199,
  description: "27-inch display",
};
// frozenProduct.price = 179; // Error: read-only property
  • Partial<T> — every property becomes optional.
  • Required<T> — every property becomes mandatory.
  • Pick<T, K> — keep only the listed properties.
  • Omit<T, K> — remove the listed properties, keep the rest.
  • Record<K, V> — build a dictionary type from keys K to values V.
  • Readonly<T> — every property becomes readonly.
Utility TypeSignatureResult
Partial<T>Partial<Product>All properties optional
Required<T>Required<Product>All properties mandatory
Pick<T, K>Pick<Product, "id"|"name">Only id and name
Omit<T, K>Omit<Product, "description">Everything except description
Record<K, V>Record<string, number>Dictionary of string keys to numbers
Readonly<T>Readonly<Product>All properties immutable

Combining Utility Types

Utility types compose naturally, so you can nest them to express fairly precise shapes, such as a read-only summary object built from only two fields of the original type.

Composing Utility Types

type ReadonlySummary = Readonly<Pick<Product, "id" | "price">>;

const priceTag: ReadonlySummary = { id: 4, price: 15.5 };
// priceTag.price = 20; // Error: read-only property
Note: Reach for a utility type before writing a brand-new interface — deriving from an existing type keeps your models in sync as they evolve.

Exercise: TypeScript Utility Types

What does TypeScript's `Partial<T>` utility type do?