TypeScript Utility Types: A Complete Guide with Examples
Master TypeScript utility types — Partial, Required, Pick, Omit, Record, Exclude, Extract, ReturnType, and more. Every built-in utility type explained with practical examples.
What Are Utility Types?
TypeScript provides a set of built-in utility types that help you transform and manipulate types. They're generic types that take one or more type parameters and return a new type. Think of them as functions, but for types instead of values.
Utility types are essential for writing DRY, maintainable TypeScript code. Instead of duplicating type definitions, you can derive new types from existing ones.
Partial<T>
Makes all properties of T optional:
interface User {
id: number;
name: string;
email: string;
age: number;
}
type PartialUser = Partial<User>;
// Equivalent to:
// {
// id?: number;
// name?: string;
// email?: string;
// age?: number;
// }
// Perfect for update functions where you only send changed fields
function updateUser(id: number, updates: Partial<User>) {
// updates can have any subset of User properties
}
updateUser(1, { name: "Alice" }); // ✅
updateUser(1, { email: "a@b.com", age: 30 }); // ✅
updateUser(1, {}); // ✅
Required<T>
The opposite of Partial — makes all properties required:
interface Config {
host?: string;
port?: number;
debug?: boolean;
}
type RequiredConfig = Required<Config>;
// {
// host: string;
// port: number;
// debug: boolean;
// }
// Useful for ensuring all config values are set after merging defaults
function createServer(config: RequiredConfig) {
// All properties guaranteed to exist
console.log(`Starting on ${config.host}:${config.port}`);
}
Readonly<T>
Makes all properties read-only (cannot be reassigned):
interface User {
id: number;
name: string;
}
type ReadonlyUser = Readonly<User>;
const user: ReadonlyUser = { id: 1, name: "Alice" };
user.name = "Bob"; // ❌ Error: Cannot assign to 'name' because it is a read-only property
// Great for function parameters that shouldn't be mutated
function processUser(user: Readonly<User>) {
// Can read user.name, but can't modify it
console.log(user.name);
}
Pick<T, K>
Creates a type with only the specified properties from T:
interface User {
id: number;
name: string;
email: string;
password: string;
createdAt: Date;
}
type PublicUser = Pick<User, "id" | "name" | "email">;
// {
// id: number;
// name: string;
// email: string;
// }
// Perfect for API responses that shouldn't include sensitive data
function getPublicProfile(user: User): PublicUser {
return {
id: user.id,
name: user.name,
email: user.email,
};
}
Omit<T, K>
The opposite of Pick — creates a type with all properties except the specified ones:
type UserWithoutPassword = Omit<User, "password">;
// {
// id: number;
// name: string;
// email: string;
// createdAt: Date;
// }
// Create a type for new user input (no id or createdAt)
type CreateUserInput = Omit<User, "id" | "createdAt">;
// {
// name: string;
// email: string;
// password: string;
// }
Record<K, T>
Creates a type with keys of type K and values of type T:
// String keys, number values
type Scores = Record<string, number>;
const scores: Scores = {
alice: 95,
bob: 87,
charlie: 92,
};
// Union keys
type Status = "pending" | "active" | "inactive";
type StatusLabels = Record<Status, string>;
const labels: StatusLabels = {
pending: "Pending Review",
active: "Active",
inactive: "Deactivated",
};
// Complex values
type UserMap = Record<string, User>;
const users: UserMap = {
"user-1": { id: 1, name: "Alice", email: "a@b.com", password: "...", createdAt: new Date() },
};
// Useful for lookup tables, dictionaries, and maps
type HttpMethods = "GET" | "POST" | "PUT" | "DELETE";
type RouteHandlers = Record<HttpMethods, (req: Request) => Response>;
Exclude<T, U>
Removes types from a union that are assignable to U:
type AllStatus = "pending" | "active" | "inactive" | "deleted";
type ActiveStatus = Exclude<AllStatus, "deleted">;
// "pending" | "active" | "inactive"
type NonNullable = Exclude<string | number | null | undefined, null | undefined>;
// string | number
// Remove specific types from a union
type Primitive = string | number | boolean | null | undefined;
type NonNullPrimitive = Exclude<Primitive, null | undefined>;
// string | number | boolean
Extract<T, U>
The opposite of Exclude — keeps only types assignable to U:
type AllTypes = string | number | boolean | (() => void);
type FunctionTypes = Extract<AllTypes, Function>;
// () => void
type StringOrNumber = Extract<string | number | boolean, string | number>;
// string | number
NonNullable<T>
Removes null and undefined from a type:
type MaybeString = string | null | undefined;
type DefiniteString = NonNullable<MaybeString>;
// string
// Useful with optional chaining results
function getUser(id: number): User | null {
// ...
}
type DefiniteUser = NonNullable<ReturnType<typeof getUser>>;
// User
ReturnType<T>
Extracts the return type of a function:
function createUser(name: string, email: string) {
return {
id: Math.random(),
name,
email,
createdAt: new Date(),
};
}
type CreatedUser = ReturnType<typeof createUser>;
// {
// id: number;
// name: string;
// email: string;
// createdAt: Date;
// }
// Useful when you don't want to define a separate interface
// The function IS the source of truth for the type
Parameters<T>
Extracts the parameter types of a function as a tuple:
function greet(name: string, age: number, isAdmin: boolean) {
// ...
}
type GreetParams = Parameters<typeof greet>;
// [string, number, boolean]
// Access individual parameters
type FirstParam = Parameters<typeof greet>[0]; // string
type SecondParam = Parameters<typeof greet>[1]; // number
// Useful for wrapper functions
function logAndCall<T extends (...args: unknown[]) => unknown>(
fn: T,
...args: Parameters<T>
): ReturnType<T> {
console.log("Calling with:", args);
return fn(...args) as ReturnType<T>;
}
Awaited<T>
Unwraps the type inside a Promise:
type PromiseString = Promise<string>;
type Resolved = Awaited<PromiseString>;
// string
// Works with nested promises too
type NestedPromise = Promise<Promise<number>>;
type DeepResolved = Awaited<NestedPromise>;
// number
// Useful with async function return types
async function fetchUser(id: number): Promise<User> {
// ...
}
type FetchedUser = Awaited<ReturnType<typeof fetchUser>>;
// User
Combining Utility Types
The real power comes from combining them:
interface User {
id: number;
name: string;
email: string;
password: string;
role: "admin" | "user" | "moderator";
createdAt: Date;
updatedAt: Date;
}
// API response (no password, no timestamps)
type UserResponse = Omit<User, "password" | "createdAt" | "updatedAt">;
// Create input (no id, no timestamps)
type CreateUserInput = Omit<User, "id" | "createdAt" | "updatedAt">;
// Update input (partial, no id or timestamps)
type UpdateUserInput = Partial<Omit<User, "id" | "createdAt" | "updatedAt">>;
// Admin-only fields
type AdminUser = Pick<User, "id" | "name" | "email" | "role">;
// Read-only user for display
type DisplayUser = Readonly<Pick<User, "id" | "name" | "email">>;
// User lookup map
type UserMap = Record<string, Readonly<UserResponse>>;
Custom Utility Types
You can build your own:
// Make specific properties optional
type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
type UserWithOptionalEmail = PartialBy<User, "email">;
// email is optional, everything else required
// Make specific properties required
type RequiredBy<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
// Deep partial (recursive)
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};
// Mutable (remove readonly)
type Mutable<T> = {
-readonly [P in keyof T]: T[P];
};
// Nullable
type Nullable<T> = {
[P in keyof T]: T[P] | null;
};
Quick Reference
| Utility | Purpose | Example |
|---|---|---|
Partial<T> | All properties optional | Update functions |
Required<T> | All properties required | Config validation |
Readonly<T> | All properties read-only | Immutable data |
Pick<T, K> | Keep specific properties | API responses |
Omit<T, K> | Remove specific properties | Hide sensitive fields |
Record<K, T> | Create key-value type | Lookup tables |
Exclude<T, U> | Remove from union | Filter status types |
Extract<T, U> | Keep from union | Extract function types |
NonNullable<T> | Remove null/undefined | Strict types |
ReturnType<T> | Get function return type | Infer types |
Parameters<T> | Get function params | Wrapper functions |
Awaited<T> | Unwrap Promise | Async return types |