TypeScriptBeginner

TypeScript Utility Types Cheat Sheet

Partial, Pick, Omit, Record, and the other built-in utility types explained with practical, real-world examples instead of abstract definitions.

DevFieldGuideJune 2, 2026 (updated July 14, 2026)6 min read
Share:

TypeScript ships a set of built-in type transformations that cover most of the "I need a slightly different version of this type" situations you'll hit. Here's the practical reference.

Partial<T> — make every field optional

ts
interface User {
  id: string;
  name: string;
  email: string;
}
 
function updateUser(id: string, changes: Partial<User>) {
  // changes might only include { name: "New Name" }
}

The canonical use case: update functions that accept a subset of fields to change.

Required<T> — the opposite, make every field mandatory

ts
interface Config {
  timeout?: number;
  retries?: number;
}
 
function runWithDefaults(config: Required<Config>) {
  // both fields guaranteed present at this point
}

Useful after you've merged user input with defaults and want the type system to confirm nothing is missing.

Pick<T, K> — select a subset of fields

ts
type UserPreview = Pick<User, "id" | "name">;
// { id: string; name: string }

Omit<T, K> — the inverse, exclude fields

ts
type UserWithoutEmail = Omit<User, "email">;
// { id: string; name: string }

Pick and Omit solve the same problem from opposite directions — use whichever needs fewer keys listed.

Record<K, V> — a typed dictionary

ts
type StatusColors = Record<"pending" | "active" | "done", string>;
// { pending: string; active: string; done: string }
 
const colors: StatusColors = {
  pending: "#eab308",
  active: "#22c55e",
  done: "#64748b",
};

Record is what you reach for instead of { [key: string]: V } when you know the exact set of valid keys — TypeScript will then error if you forget one or typo a key.

Readonly<T> — prevent reassignment

ts
const config: Readonly<Config> = { timeout: 5000, retries: 3 };
config.timeout = 1000; // Error: Cannot assign to 'timeout' because it is a read-only property

Only a compile-time guarantee — it doesn't freeze the object at runtime like Object.freeze() does.

ReturnType<T> — extract a function's return type

ts
function createUser() {
  return { id: crypto.randomUUID(), createdAt: new Date() };
}
 
type NewUser = ReturnType<typeof createUser>;

Genuinely useful when the return type is inferred and complex — you get the type without duplicating the shape by hand, and it stays in sync automatically if the function changes.

Exclude<T, U> and Extract<T, U> — filtering union types

ts
type Status = "pending" | "active" | "done" | "archived";
 
type ActiveStatus = Exclude<Status, "archived">;
// "pending" | "active" | "done"
 
type FinalStatus = Extract<Status, "done" | "archived">;
// "done" | "archived"

Exclude removes members of a union that match; Extract keeps only the members that match — the same relationship as Omit/Pick, but operating on union types instead of object shapes.

NonNullable<T> — strip out null and undefined

ts
function getLength(value: string | null | undefined): number {
  const safe: NonNullable<typeof value> = value ?? "";
  return safe.length;
}

Most useful after a null-check or default value, to tell the type system explicitly that null/undefined are no longer possible at that point — even when the compiler's own narrowing doesn't already infer it.

Awaited<T> — unwrap a Promise's resolved type

ts
async function fetchUser() {
  return { id: "1", name: "Ada" };
}
 
type User = Awaited<ReturnType<typeof fetchUser>>;
// { id: string; name: string } — not Promise<{ id: string; name: string }>

Handles nested promises correctly too (Promise<Promise<T>> resolves to T), which matters because awaiting a promise that itself resolves to a promise flattens automatically at runtime — Awaited mirrors that at the type level.

UtilityWhat it does
Partial<T>Every field becomes optional
Required<T>Every field becomes mandatory
Pick<T, K> / Omit<T, K>Select or exclude specific fields
Record<K, V>A typed dictionary with known keys
Readonly<T>Compile-time-only immutability
ReturnType<T> / Awaited<T>Extract a function's (resolved) return type

Combining them

These compose naturally:

ts
type UserUpdate = Partial<Omit<User, "id">>;
// every field optional except id is excluded entirely

That's the real payoff — instead of hand-writing a new interface for every variation of a shape you need, you derive it from one source of truth.

These utility types earn their keep most visibly during a real incremental JavaScript-to-TypeScript migration — deriving new shapes from existing ones instead of hand-writing near-duplicate interfaces is exactly the leverage that makes converting a large codebase file by file tractable.

Parameters<T> and ConstructorParameters<T>

Two less commonly needed but genuinely useful extraction utilities, for when you need a function or class constructor's argument types rather than its return type:

ts
function createUser(name: string, age: number, active: boolean) {
  return { name, age, active };
}
 
type CreateUserArgs = Parameters<typeof createUser>;
// [name: string, age: number, active: boolean]
 
class ApiClient {
  constructor(baseUrl: string, timeout: number) {}
}
 
type ApiClientArgs = ConstructorParameters<typeof ApiClient>;
// [baseUrl: string, timeout: number]

These come up most often when writing a wrapper function that needs to accept "whatever arguments the wrapped function accepts" without duplicating the parameter list by hand — a logging wrapper, a retry wrapper, or a factory function that forwards its arguments to an underlying constructor.

InstanceType<T> — the type a constructor produces

The counterpart to ConstructorParameters — instead of extracting what a class constructor accepts, this extracts what it produces:

ts
type ApiClientInstance = InstanceType<typeof ApiClient>;
// the actual instance type, equivalent to just writing "ApiClient" here,
// but useful when working generically with a class passed as a value

This matters specifically in generic code that receives a class itself as a parameter (a factory pattern, a dependency injection container) rather than a fixed, named class — InstanceType<T> lets that generic code express "the type this class produces" without knowing the concrete class name ahead of time.

Common mistakes

Common mistakes
  • Reaching for Partial<T> on a type that should never actually have optional fields at runtime — it's meant for describing an update payload, not for weakening a type just to make an error go away.
  • Confusing Readonly<T>'s compile-time-only guarantee with real immutability, then being surprised an object still mutates through a differently-typed reference to the same underlying object.
  • Nesting Omit/Pick several levels deep instead of defining an intermediate named type — technically works, but becomes unreadable in error messages and hover tooltips past two or three levels of composition.
  • Using Record<string, V> when the actual key set is known and finite — this silently allows any string key and loses the "did you typo a key" safety that a union of literal keys would have caught.
Advertisement

Frequently Asked Questions

Advertisement
DevFieldGuide
DevFieldGuide

Editorial Team

Practical tutorials and developer tools, written and maintained by the DevFieldGuide team.

Enjoyed this article?

Get the next one straight to your inbox, along with the best of what we publish each week.

Related Articles

More in TypeScript

View all