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 propertyReturnType<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>;
// HttpClientUppercase, 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 Type | What 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.