TypeScript's built-in utility types are the power tools of the type system. They transform existing types into new shapes without duplicating declarations, enabling everything from partial form state to API response filtering. Yet many developers only know Partial and Pick, leaving the full toolkit largely unexplored. Understanding the complete set of utility types — and how to build your own — is the difference between fighting the compiler and making it work for you.
Our free interactive TypeScript utility types cheat sheet maps fifty-plus utilities across nine architectural categories. Each entry includes the type-level signature, a concise explanation, and a copyable code example. The Architect's Drafting Room aesthetic — deep blueprint slate background, technical grid overlay, TypeScript blue and copper accents, Chakra Petch display headings — turns type exploration into structural engineering. Everything runs in your browser. No compilation server, no signup, no data collection.
Why Utility Types Matter
TypeScript's type system is structural, not nominal. This means two types with the same shape are considered compatible regardless of where they were declared. While this reduces ceremony, it also means that type transformations — making properties optional, picking a subset, extracting return types — must be expressible at the type level. Utility types provide this expressivity.
Consider a typical application. You have a User interface with a dozen fields. Your API returns full User objects. Your profile form needs a Partial<User>. Your public profile page needs Pick<User, "id" | "name" | "avatar">. Your admin dashboard needs Omit<User, "passwordHash">. Without utility types, you would maintain four separate interfaces and pray they stay in sync. With utility types, you derive everything from a single source of truth.
Beyond the built-in utilities, the same patterns enable custom transformations. DeepPartial for nested optionality, branded types for nominal safety, UnionToIntersection for advanced composition — these are not exotic edge cases. They are everyday tools for teams working with complex type domains.
Basic Modifiers — Partial, Required, Readonly
The three foundational utility types modify the optionality and mutability of object properties. They are implemented using mapped types, which means you can build your own variants once you understand the pattern.
Partial<T>
Partial makes every property optional. It is the standard tool for update operations where you only provide the fields that changed.
interface User {
id: number;
name: string;
email: string;
}
type UserUpdate = Partial<User>;
// { id?: number; name?: string; email?: string }
const update: UserUpdate = { name: "Alice" }; Required<T>
Required strips the optionality modifier from every property. It is the inverse of Partial and useful when you have validated that all optional fields are now present.
interface Config {
host?: string;
port?: number;
}
type StrictConfig = Required<Config>;
// { host: string; port: number } Readonly<T>
Readonly prevents reassignment of properties after object creation. It is essential for immutable state patterns and functional programming workflows.
interface Point {
x: number;
y: number;
}
type ImmutablePoint = Readonly<Point>;
const p: ImmutablePoint = { x: 0, y: 0 };
// p.x = 1; // Error: Cannot assign to 'x' Mutable<T> (Custom)
TypeScript does not ship a built-in Mutable type, but it is trivial to construct using the minus modifier on readonly.
type Mutable<T> = { -readonly [K in keyof T]: T[K]; };
interface Frozen {
readonly id: number;
readonly name: string;
}
type Thawed = Mutable<Frozen>;
// { id: number; name: string } Property Selection — Pick and Omit
When you need a subset of an existing type, Pick and Omit are the right tools. They are complementary: Pick selects specific keys to keep; Omit selects specific keys to remove.
Pick<T, K>
Pick creates a subtype containing only the keys you specify. It is the type-level equivalent of SQL SELECT.
interface User {
id: number;
name: string;
email: string;
password: string;
}
type PublicUser = Pick<User, "id" | "name">;
// { id: number; name: string } Omit<T, K>
Omit creates a subtype by removing specific keys. It is ideal for stripping internal fields before sending data to the client.
type SafeUser = Omit<User, "password">;
// { id: number; name: string; email: string } Both Pick and Omit are implemented using mapped types and conditional types, which means they compose naturally with other utilities.
Key-Value Builders — Record and Mapped Types
Record<K, T> constructs an object type with uniform value types across all keys. It is the go-to type for dictionaries, lookup tables, and maps.
type PageInfo = { title: string; path: string };
type Pages = Record<"home" | "about" | "contact", PageInfo>;
const pages: Pages = {
home: { title: "Home", path: "/" },
about: { title: "About", path: "/about" },
contact: { title: "Contact", path: "/contact" },
}; Behind Record lies the mapped type syntax [P in K]: T. This syntax is the engine for most custom utilities. You can remap keys, filter keys conditionally, and even transform key names using template literal types.
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
interface Person { name: string; age: number; }
type PersonGetters = Getters<Person>;
// { getName: () => string; getAge: () => number } Set Operations on Unions — Exclude, Extract, NonNullable
Union types are the backbone of TypeScript's flexibility. The set operation utilities let you manipulate unions like mathematical sets.
Exclude<T, U>
Removes types from T that are assignable to U. This is set difference.
type Status = "pending" | "success" | "error" | "loading";
type FinalStatus = Exclude<Status, "pending" | "loading">;
// "success" | "error" Extract<T, U>
Extracts types from T that are assignable to U. This is set intersection.
type Mixed = string | number | boolean | Function;
type OnlyFunctions = Extract<Mixed, Function>;
// Function NonNullable<T>
Removes null and undefined from a union. After a null check, this utility confirms the narrowed type.
type MaybeString = string | null | undefined;
type DefiniteString = NonNullable<MaybeString>;
// string Function Introspection — Parameters, ReturnType, InstanceType
These utilities extract information from function and constructor types. They are indispensable for wrapper functions, proxies, and type-safe higher-order operations.
Parameters<T>
Extracts parameter types as a tuple.
type Fn = (a: string, b: number) => void;
type Args = Parameters<Fn>;
// [string, number] ReturnType<T>
Extracts the return type of a function.
function createUser(name: string) {
return { id: 1, name };
}
type User = ReturnType<typeof createUser>;
// { id: number; name: string } InstanceType<T>
Extracts the instance type from a constructor.
class Container<T> {
value!: T;
}
type StringContainer = InstanceType<typeof Container<string>>;
// Container<string> String Manipulation at the Type Level
TypeScript 4.1 introduced intrinsic string manipulation types: Uppercase, Lowercase, Capitalize, and Uncapitalize. Combined with template literal types, they enable powerful string-derived type generation.
type EventName<T extends string> = `on${Capitalize<T>}`;
type ClickEvent = EventName<"click">;
// "onClick"
type HttpMethod = "get" | "post";
type Endpoint = `/api/${HttpMethod}`;
// "/api/get" | "/api/post" These types operate at compile time only. They generate new string literal types from existing ones, enabling type-safe routing, event naming, and API client generation.
Deep and Recursive Utilities
The built-in Partial, Required, and Readonly only operate at the top level. For nested objects, you need recursive custom utilities.
DeepPartial<T>
type DeepPartial<T> = {
[P in keyof T]?: T[P] extends object ? DeepPartial<T[P]> : T[P];
};
interface Config {
server: { host: string; port: number; ssl: { cert: string } };
}
type PartialConfig = DeepPartial<Config>;
// All properties at all depths are optional DeepReadonly<T>
type DeepReadonly<T> = {
readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];
};
interface Node {
value: number;
next?: Node;
}
type FrozenNode = DeepReadonly<Node>;
// All levels become readonly These recursive types can hit recursion depth limits on deeply nested objects. For production use, consider adding a depth limit or using a library like type-fest.
Advanced Custom Patterns
Beyond the standard transformations, several custom patterns solve specific architectural problems.
Branded Types
Branded types create nominal typing within TypeScript's structural system. They prevent accidental mixing of semantically different values.
type Brand<K, T> = K & { __brand: T };
type UserId = Brand<number, "UserId">;
type OrderId = Brand<number, "OrderId">;
function getUser(id: UserId) {}
const uid = 1 as UserId;
// getOrder(uid); // Error! UnionToIntersection
Converts a union to an intersection using contravariant inference.
type UnionToIntersection<U> =
(U extends any ? (k: U) => void : never) extends
(k: infer I) => void ? I : never;
type U = { a: string } | { b: number };
type I = UnionToIntersection<U>;
// { a: string } & { b: number } OptionalKeys and RequiredKeys
type OptionalKeys<T> = {
[K in keyof T]-?: {} extends Pick<T, K> ? K : never;
}[keyof T];
type RequiredKeys<T> = {
[K in keyof T]-?: {} extends Pick<T, K> ? never : K;
}[keyof T]; Interactive TypeScript Utility Types Cheat Sheet
Reading about utility types is useful, but exploring them interactively is faster. Our free TypeScript Utility Types Cheat Sheet organizes every concept from this article into a searchable, filterable interface. Click any category tab to explore a territory of the type system. Use the search bar to find specific syntax instantly. Click the Copy button on any code block to grab the example and paste it into your editor.
The Architect's Drafting Room aesthetic makes the interface memorable. Deep blueprint slate background evokes a technical drawing studio. Faint grid lines suggest engineering precision. Drifting geometric shapes mark key waypoints. Each category receives a distinct accent color — gold for basic modifiers, teal for property selection, sky blue for key-value builders, violet for set operations, rose for function extraction, amber for this-related types, lime for string manipulation, copper for async and deep utilities, and slate for advanced patterns.
Related Developer Tools
TypeScript utility types are just one piece of the modern developer toolkit. Explore these related references to round out your workflow:
- TypeScript Types Cheat Sheet — 65+ type concepts covering basic types, interfaces, generics, mapped types, and conditional types
- React Hooks Cheat Sheet — Built-in and custom hooks with patterns and rules
- React Performance Patterns Cheat Sheet — 25+ optimization patterns across 6 categories
- JavaScript Array Methods Cheat Sheet — 40+ array methods with mutability and chainability notes
- JavaScript Error Handling Patterns Cheat Sheet — 45+ patterns covering try/catch, async/await, Promise errors, and custom errors
- CSS Grid & Flexbox Cheat Sheet — 44 entries across 8 categories with layout patterns
- DevOps Commands Cheat Sheet — 75+ commands across Docker, Kubernetes, AWS, Helm, and Terraform
- Node.js Built-in Modules Cheat Sheet — 70+ Node.js APIs across fs, path, http, events, stream, buffer, crypto, os, and more
Conclusion
TypeScript utility types transform the type system from a static checker into a programmable design tool. From simple optionality changes with Partial and Required to deep recursive transformations and contravariant magic with UnionToIntersection, the expressive power available at the type level is remarkable. The key is to build your knowledge incrementally — master the built-in utilities first, then explore custom patterns as you encounter real problems that require them.
Keep the TypeScript Utility Types Cheat Sheet bookmarked. The next time you need to extract the return type of a function, make a nested object partially optional, or brand an ID to prevent type confusion, it will be one search away.