TypeScript Utility Types

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

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?