Contents

Programming Fundamentals › Type Systems

Utility Types

Built-in TypeScript type transformers like Partial, Pick and Record.

Also known as: TypeScript utility types, Partial, Pick, Omit, Record, Readonly, mapped types

TypeScript ships with utility types: built-in generic types that transform other types, so you don’t repeat yourself or hand-write near-copies.

Start from one type:

interface User {
  id: number;
  name: string;
  email: string;
  role: "admin" | "member";
}
UtilityResultExample
Partial<T>All properties optionalPartial<User>: for an update payload
Required<T>All properties required
Readonly<T>All properties read-onlyReadonly<User>
Pick<T, K>Only the listed propertiesPick<User, "id" | "name">
Omit<T, K>Everything except the listed onesOmit<User, "id">: a “new user” before it gets an id
Record<K, V>An object type with keys K and values VRecord<string, number>
NonNullable<T>Removes null and undefined
ReturnType<F>The return type of a function typeReturnType<typeof getUser>
Parameters<F>A tuple of a function’s parameter types
Awaited<T>What a promise resolves toAwaited<Promise<User>> is User
function updateUser(id: number, changes: Partial<Omit<User, "id">>) { ... }

updateUser(7, { name: "Ana" });           // ok: any subset of fields except id

const permissions: Record<User["role"], string[]> = {
  admin: ["read", "write", "delete"],
  member: ["read"],
};                                       // error if a role is missing: exhaustive by construction

Why they’re useful

  • One source of truth. Derive related types from the main one, so when User changes, the others follow.
  • Fewer bugs: Record over a union of keys forces you to handle every case.
  • They compose: combine them as shown.

Cautions

  • Don’t build a tower of nested utility types that’s unreadable. Name intermediate types with an alias (type aliases).
  • Partial allows {}, which is sometimes not what you mean.
  • These are compile-time only, and don’t validate data at runtime (runtime validation).
  • You can write your own using mapped and conditional types when the built-ins fall short.