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 mandatoryPick 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,
};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.
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 propertyExercise: TypeScript Utility Types
What does TypeScript's `Partial<T>` utility type do?