TypeScript Utility Types Explained with Examples

TypeScript ships with a powerful set of built-in utility types that transform existing types without writing new interfaces from scratch. Here is every one you need to know, with real-world examples.

Partial<T>

Makes every property in T optional. Perfect for update/patch functions where you only send the fields that changed.

interface User {
  id: number;
  name: string;
  email: string;
}

// All fields become optional
type UpdateUserPayload = Partial<User>;

function updateUser(id: number, data: Partial<User>) {
  // data.name, data.email are both string | undefined
  return fetch(`/api/users/${id}`, {
    method: "PATCH",
    body: JSON.stringify(data),
  });
}

// Valid — only send what changed
updateUser(1, { name: "Alice" });

Required<T>

The opposite of Partial — makes every property required. Useful when your base type has optional fields but a specific context demands all of them.

interface Config {
  host?: string;
  port?: number;
  debug?: boolean;
}

// After validation, everything must be present
type ValidatedConfig = Required<Config>;

function startServer(config: ValidatedConfig) {
  // config.host is guaranteed to be string, not string | undefined
  console.log(`Listening on ${config.host}:${config.port}`);
}

Pick<T, K>

Create a type with only the specified keys from T. Great for building DTOs and API response shapes.

interface User {
  id: number;
  name: string;
  email: string;
  passwordHash: string;
  createdAt: Date;
}

// Only expose safe fields in API responses
type PublicUser = Pick<User, "id" | "name" | "email">;

// Result: { id: number; name: string; email: string }

Omit<T, K>

The inverse of Pick — create a type with all keysexcept the specified ones.

// Everything except sensitive fields
type SafeUser = Omit<User, "passwordHash">;

// Great for "create" payloads where ID is auto-generated
type CreateUserInput = Omit<User, "id" | "createdAt">;

Record<K, V>

Construct a type with a set of keys K and value type V. Cleaner than manual index signatures.

// Map HTTP methods to handler functions
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";
type RouteHandlers = Record<HttpMethod, (req: Request) => Response>;

// Map status to list of items
type StatusGroups = Record<"active" | "archived" | "draft", Item[]>;

// Dynamic string keys
type Env = Record<string, string | undefined>;
const env: Env = process.env;

Readonly<T>

Makes all properties readonly. Prevents accidental mutation.

interface AppState {
  user: User | null;
  theme: "light" | "dark";
}

function getInitialState(): Readonly<AppState> {
  return { user: null, theme: "dark" };
}

const state = getInitialState();
state.theme = "light"; // Error: Cannot assign to 'theme' because it is a read-only property

ReturnType<T>

Extract the return type of a function. Extremely useful when you don't control the function (e.g., a library).

function createUser(name: string, email: string) {
  return { id: Math.random(), name, email, createdAt: new Date() };
}

// Infer the return type without writing it manually
type CreatedUser = ReturnType<typeof createUser>;
// { id: number; name: string; email: string; createdAt: Date }

// Works with async functions too — but gives you the Promise wrapper
type AsyncResult = ReturnType<typeof fetch>;
// Promise<Response>

Parameters<T>

Extract function parameters as a tuple type.

function searchUsers(query: string, limit: number, offset: number) {
  // ...
}

type SearchParams = Parameters<typeof searchUsers>;
// [query: string, limit: number, offset: number]

// Useful for wrapper functions
function loggedSearch(...args: Parameters<typeof searchUsers>) {
  console.log("Searching:", args);
  return searchUsers(...args);
}

Exclude<T, U>

Remove types from a union that are assignable to U.

type Status = "active" | "inactive" | "banned" | "pending";

// Remove "banned" from allowed statuses
type AllowedStatus = Exclude<Status, "banned">;
// "active" | "inactive" | "pending"

// Remove multiple
type SimpleStatus = Exclude<Status, "banned" | "pending">;
// "active" | "inactive"

Extract<T, U>

The opposite of Exclude — keep only types assignable to U.

type Input = string | number | boolean | null | undefined;

// Keep only the primitive types
type Primitives = Extract<Input, string | number | boolean>;
// string | number | boolean

// Extract function types from a union
type Mixed = string | (() => void) | number | ((x: number) => string);
type Functions = Extract<Mixed, Function>;
// (() => void) | ((x: number) => string)

NonNullable<T>

Remove null and undefined from a type.

type MaybeUser = User | null | undefined;

type DefiniteUser = NonNullable<MaybeUser>;
// User

// Common pattern: after a null check
function getUser(id: number): User | null { /* ... */ }

const user = getUser(1);
if (user) {
  // TypeScript narrows to NonNullable automatically here
  processUser(user);
}

Awaited<T>

Unwrap the resolved type of a Promise. Handles nested promises too.

type A = Awaited<Promise<string>>;
// string

type B = Awaited<Promise<Promise<number>>>;
// number (recursively unwraps)

// Real-world: extract the data type from an async function
async function fetchUsers() {
  const res = await fetch("/api/users");
  return res.json() as Promise<User[]>;
}

type Users = Awaited<ReturnType<typeof fetchUsers>>;
// User[]

ConstructorParameters<T> & InstanceType<T>

Work with class constructor types.

class HttpClient {
  constructor(public baseUrl: string, public timeout: number) {}
}

type ClientArgs = ConstructorParameters<typeof HttpClient>;
// [baseUrl: string, timeout: number]

type ClientInstance = InstanceType<typeof HttpClient>;
// HttpClient

Uppercase, Lowercase, Capitalize, Uncapitalize

Built-in template literal manipulation types (since TypeScript 4.1).

type Event = "click" | "focus" | "blur";

type OnEvent = `on${Capitalize<Event>}`;
// "onClick" | "onFocus" | "onBlur"

type UpperEvent = Uppercase<Event>;
// "CLICK" | "FOCUS" | "BLUR"

type LowerStatus = Lowercase<"ACTIVE" | "INACTIVE">;
// "active" | "inactive"

Combining Utility Types

The real power emerges when you compose utility types together.

interface Post {
  id: number;
  title: string;
  body: string;
  authorId: number;
  tags: string[];
  publishedAt: Date | null;
}

// Create input: no id (auto-generated), everything else required
type CreatePostInput = Omit<Post, "id">;

// Update input: no id in body (it's in the URL), everything optional
type UpdatePostInput = Partial<Omit<Post, "id">>;

// List response: only summary fields
type PostSummary = Pick<Post, "id" | "title" | "authorId" | "publishedAt">;

// Published posts always have a date
type PublishedPost = Omit<Post, "publishedAt"> & { publishedAt: Date };

// Make a readonly version for state management
type FrozenPost = Readonly<Post>;

Cheatsheet Table

Utility TypeWhat It Does
Partial<T>All properties optional
Required<T>All properties required
Readonly<T>All properties readonly
Pick<T, K>Keep only keys K
Omit<T, K>Remove keys K
Record<K, V>Object with keys K and values V
Exclude<T, U>Remove U from union T
Extract<T, U>Keep only U from union T
NonNullable<T>Remove null and undefined
ReturnType<T>Function return type
Parameters<T>Function parameter types as tuple
Awaited<T>Unwrap Promise type

Build Faster with Our Dev Tools

Validate your JSON API responses, format code snippets, or convert data types with our free browser-based tools.