cheat sheet
Utility Types
TypeScript's built-in generic utility types that transform existing types into new ones. Covers Partial, Required, Readonly, Record, Pick, Omit, Exclude, Extract, ReturnType, Awaited, and more.
Utility Types
What it is
TypeScript ships a collection of built-in generic utility types that transform existing types into new ones. They are defined using mapped types, conditional types, and infer — all available in the TypeScript standard library without any import. Understanding them eliminates the need to repeat common type manipulations and helps you compose complex types from simpler ones.
Object utility types
Partial<T>
Makes all properties of T optional. Useful for update/patch payloads. Internal implementation:
type Partial<T> = { [K in keyof T]?: T[K] };
interface User {
id: number;
name: string;
email: string;
role: "admin" | "user";
}
type UserPatch = Partial<User>;
// { id?: number; name?: string; email?: string; role?: "admin" | "user" }
function updateUser(id: number, patch: Partial<User>): Promise<User> {
return fetch(`/users/${id}`, {
method: "PATCH",
body: JSON.stringify(patch),
}).then((r) => r.json());
}
updateUser(1, { name: "Alice" }); // Only name — rest are optional
Required<T>
Makes all properties required (removes all ?). The inverse of Partial. Internal implementation uses the -? modifier to strip optionality:
type Required<T> = { [K in keyof T]-?: T[K] };
interface Config {
host?: string;
port?: number;
debug?: boolean;
}
type ResolvedConfig = Required<Config>;
// { host: string; port: number; debug: boolean }
function resolveConfig(cfg: Config): ResolvedConfig {
return {
host: cfg.host ?? "localhost",
port: cfg.port ?? 3000,
debug: cfg.debug ?? false,
};
}
Readonly<T>
Makes all properties readonly — they cannot be reassigned after creation. Implementation:
type Readonly<T> = { readonly [K in keyof T]: T[K] };
interface Point { x: number; y: number }
const origin: Readonly<Point> = { x: 0, y: 0 };
origin.x = 1; // Error — Cannot assign to 'x' because it is a read-only property
Useful for function parameters you want to protect from mutation:
function translate(point: Readonly<Point>, dx: number, dy: number): Point {
// point.x += dx; // Error — can't mutate
return { x: point.x + dx, y: point.y + dy }; // must return new object
}
Record<K, V>
Constructs an object type whose keys are K and values are V. Record is the canonical "map" type — its implementation is a one-line mapped type:
type Record<K extends keyof any, V> = { [P in K]: V };
The keyof any constraint allows K to be string | number | symbol (the only valid object key types).
type Role = "admin" | "user" | "moderator";
type Permissions = Record<Role, string[]>;
const permissions: Permissions = {
admin: ["read", "write", "delete"],
user: ["read"],
moderator: ["read", "write"],
};
// Also useful for dictionaries
type Cache = Record<string, unknown>;
const cache: Cache = {};
cache["key1"] = { data: 42 };
Pick<T, K>
Creates a type with only the specified keys from T. Implementation:
type Pick<T, K extends keyof T> = { [P in K]: T[P] };
The K extends keyof T constraint is what makes Pick safer than a hand-rolled equivalent — invalid keys are flagged at the call site.
type UserPreview = Pick<User, "id" | "name">;
// { id: number; name: string }
function renderCard(user: Pick<User, "id" | "name">): string {
return `<div>${user.id}: ${user.name}</div>`;
}
Omit<T, K>
Creates a type with all keys from T except those in K. The inverse of Pick. Internal implementation is Pick over Exclude:
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
Note that K extends keyof any is intentionally loose — Omit silently accepts keys that don't exist on T, which is a known papercut. For strict checking, see Except from type-fest.
type UserWithoutId = Omit<User, "id">;
// { name: string; email: string; role: "admin" | "user" }
type CreateUserPayload = Omit<User, "id">; // id is generated server-side
Exclude<T, U>
From a union type T, removes all members assignable to U. Built from a distributive conditional type — see mapped-conditional-types for why distribution is what makes this work member-by-member:
type Exclude<T, U> = T extends U ? never : T;
type Status = "pending" | "active" | "inactive" | "deleted";
type ActiveStatus = Exclude<Status, "deleted" | "inactive">;
// "pending" | "active"
type NonNullish = Exclude<string | number | null | undefined, null | undefined>;
// string | number
Extract<T, U>
From a union type T, keeps only members assignable to U. The inverse of Exclude:
type Extract<T, U> = T extends U ? T : never;
type StringOrNumber = string | number | boolean | object;
type Primitives = Extract<StringOrNumber, string | number>;
// string | number
type SuccessResponse = Extract<
{ status: "ok"; data: string } | { status: "error"; message: string },
{ status: "ok" }
>;
// { status: "ok"; data: string }
NonNullable<T>
Removes null and undefined from a type. Internal implementation (TS 4.8+ uses an intersection trick for better inference):
type NonNullable<T> = T & {};
// Older form:
// type NonNullable<T> = T extends null | undefined ? never : T;
type MaybeString = string | null | undefined;
type DefiniteString = NonNullable<MaybeString>; // string
function assertNonNull<T>(value: T): NonNullable<T> {
if (value == null) throw new Error("Value is null or undefined");
return value as NonNullable<T>;
}
Function utility types
ReturnType<T>
Extracts the return type of a function type T. Implementation uses infer in the return position:
type ReturnType<T extends (...args: any) => any> =
T extends (...args: any) => infer R ? R : any;
function createUser(name: string, role: string) {
return { id: Math.random(), name, role, createdAt: new Date() };
}
type CreatedUser = ReturnType<typeof createUser>;
// { id: number; name: string; role: string; createdAt: Date }
// Useful when you don't want to define the return type separately
Parameters<T>
Extracts the parameter types of a function type T as a tuple. Implementation uses infer over the rest parameter:
type Parameters<T extends (...args: any) => any> =
T extends (...args: infer P) => any ? P : never;
function login(username: string, password: string, rememberMe: boolean): void {}
type LoginArgs = Parameters<typeof login>;
// [username: string, password: string, rememberMe: boolean]
// Re-use parameters in a wrapper function
function withLogging(fn: (...args: Parameters<typeof login>) => void) {
return (...args: Parameters<typeof login>) => {
console.log("Calling login with", args[0]);
fn(...args);
};
}
ConstructorParameters<T>
Extracts the constructor parameter types of a class as a tuple, mirroring Parameters<T> but for new signatures. Useful in generic factory functions that need to forward constructor arguments without hardcoding them. Implementation:
type ConstructorParameters<T extends abstract new (...args: any) => any> =
T extends abstract new (...args: infer P) => any ? P : never;
class HttpClient {
constructor(
public baseUrl: string,
public timeout: number,
public headers: Record<string, string>
) {}
}
type HttpClientArgs = ConstructorParameters<typeof HttpClient>;
// [baseUrl: string, timeout: number, headers: Record<string, string>]
InstanceType<T>
Extracts the instance type produced by a constructor type T — essentially the type of new T(). Pair it with ConstructorParameters<T> when writing generic factory helpers that need to return the correctly typed instance. Implementation:
type InstanceType<T extends abstract new (...args: any) => any> =
T extends abstract new (...args: any) => infer R ? R : any;
type HttpClientInstance = InstanceType<typeof HttpClient>;
// HttpClient
// Useful in generic factory patterns
function createService<T extends abstract new (...args: any[]) => any>(
cls: T,
...args: ConstructorParameters<T>
): InstanceType<T> {
return new (cls as any)(...args);
}
ThisParameterType<T> and OmitThisParameter<T>
ThisParameterType<T> extracts the explicit this parameter type from a function signature; OmitThisParameter<T> strips it, giving you the callable signature without a this constraint. Use them when you need to bind or adapt functions that declare an explicit this type.
function greet(this: { name: string }, greeting: string): string {
return `${greeting}, ${this.name}`;
}
type ThisType = ThisParameterType<typeof greet>; // { name: string }
type NoThis = OmitThisParameter<typeof greet>; // (greeting: string) => string
ThisType<T>
ThisType<T> is a special marker utility — it has no runtime, and unlike the others it isn't a transformation. Instead, when it appears in a contextualType for an object literal, it tells the compiler to use T as the this type for every method in that literal. The classic use case is Vue 2-style options objects or any "configuration object whose methods see each other through this."
type ObjectDescriptor<D, M> = {
data?: D;
methods?: M & ThisType<D & M>; // <-- methods can `this.foo` over D and M
};
function makeObject<D, M>(desc: ObjectDescriptor<D, M>): D & M {
return { ...(desc.data ?? {} as D), ...(desc.methods ?? {} as M) } as D & M;
}
const obj = makeObject({
data: { x: 0, y: 0 },
methods: {
moveBy(dx: number, dy: number) {
this.x += dx;
this.y += dy;
// this is inferred as { x: number; y: number } & methods — no annotation needed
},
},
});
obj.moveBy(5, 7);
console.log(obj);
Output:
{ x: 5, y: 7, moveBy: [Function: moveBy] }
Reach for ThisType only when you control the helper that consumes the object literal. Outside of that "options object" pattern it has no use.
Promise utility types
Awaited<T>
Recursively unwraps the type that a Promise resolves to. Handles nested promises. Internal implementation (added in TS 4.5) uses recursive conditional types with a then-method check, mirroring the spec's "thenable" semantics:
type Awaited<T> =
T extends null | undefined ? T :
T extends object & { then(onfulfilled: infer F, ...args: infer _): any } ?
F extends (value: infer V, ...args: infer _) => any ? Awaited<V> : never :
T;
type A = Awaited<Promise<string>>; // string
type B = Awaited<Promise<Promise<number>>>; // number
type C = Awaited<string>; // string (not a promise, passthrough)
async function fetchUser(): Promise<User> { /* ... */ return {} as User; }
type FetchedUser = Awaited<ReturnType<typeof fetchUser>>; // User
String manipulation types
These operate on string literal types. They are intrinsic — implemented in the compiler itself, not as user-land conditional types — so you cannot inspect their definition in lib.es5.d.ts. They are the four primitives every higher-level template-literal helper composes on top of.
type Upper = Uppercase<"hello">; // "HELLO"
type Lower = Lowercase<"WORLD">; // "world"
type Cap = Capitalize<"typescript">; // "Typescript"
type Uncap = Uncapitalize<"TypeScript">; // "typeScript"
// Practical: generate CSS class names from a union
type Colors = "red" | "green" | "blue";
type ColorClass = `text-${Colors}`; // "text-red" | "text-green" | "text-blue"
type CssVar = `--color-${Lowercase<"RED" | "GREEN">}`; // "--color-red" | "--color-green"
A subtle note: when fed a non-literal string, these intrinsics return string — they only narrow when given a literal type. See template-literal-types for the full pattern library these enable. For richer case conversions (CamelCase, KebabCase, SnakeCase, PascalCase), use type-fest.
Composition patterns
Partial + Pick (partial update of specific fields)
Combining Partial and Pick lets you express "zero or more of these specific fields" — a common shape for PATCH-style API payloads where only a named subset of properties is editable.
type PartialPick<T, K extends keyof T> = Partial<Pick<T, K>>;
// Allow updating only name and email, both optional
type UserContactUpdate = PartialPick<User, "name" | "email">;
// { name?: string; email?: string }
Building Mutable<T> from scratch
The standard library doesn't include Mutable (the inverse of Readonly), but it's easy to build using a mapped type with the -readonly modifier:
type Mutable<T> = {
-readonly [K in keyof T]: T[K];
};
interface FrozenPoint {
readonly x: number;
readonly y: number;
}
type MovablePoint = Mutable<FrozenPoint>;
// { x: number; y: number } — readonly removed
const p: MovablePoint = { x: 0, y: 0 };
p.x = 10; // OK now
DeepPartial<T>
The built-in Partial is shallow. A recursive version:
type DeepPartial<T> = T extends object
? { [K in keyof T]?: DeepPartial<T[K]> }
: T;
interface Config {
server: { host: string; port: number };
db: { url: string; pool: number };
}
type PartialConfig = DeepPartial<Config>;
// { server?: { host?: string; port?: number }; db?: { url?: string; pool?: number } }
Combining utility types
Utility types compose with & (intersection) and with each other as generic arguments, letting you build precise shapes from a single source type. Prefer composition over duplicating interface definitions when derived types share an origin.
interface ApiResponse<T> {
data: T;
meta: { total: number; page: number };
errors: string[];
}
// A minimal public response with no errors field
type PublicResponse<T> = Readonly<Omit<ApiResponse<T>, "errors">>;
// Make only the meta required, data optional
type PartialResponse<T> = Required<Pick<ApiResponse<T>, "meta">> & Partial<Pick<ApiResponse<T>, "data">>;
Beyond the standard library
The standard library is deliberately small. For a much wider set of community utilities — PartialDeep, RequireAtLeastOne, Merge, Tagged, JsonValue, Get<T, "a.b.c">, etc. — see type-fest. The same article includes a side-by-side comparison of when to reach for the built-ins versus the community pack.
Common pitfalls
Partialis shallow —Partial<{ a: { b: number } }>makesaoptional buta.bstays required. UsePartialDeepfromtype-festor a hand-rolled recursive version.Omitaccepts unknown keys silently — typos inKproduce a result identical to the input. PreferExceptfromtype-festfor strict checking.Pick<T, K>plus a union widens — passingK = "a" | "b" | "missing"errors immediately; that's the good case. The bad case isK extends stringin your own utilities, which lets typos through.Requireddiscards the?markers but not theundefinedin unions —Required<{ a?: string | undefined }>is{ a: string | undefined }, not{ a: string }. Combine withNonNullableif needed.Record<string, V>is too loose —keyof Record<string, V>isstring, dropping any literal narrowness. UseRecord<"a" | "b", V>(or just an explicit object type) when you want enumerable keys.ReturnTypeover an overloaded function — picks the last overload only. For all overload returns, use an explicit union ortype-fest'sOverloadedReturnType.Parameterswidens optional parameters —Parameters<(x?: number) => void>is[x?: number], not[number]. Destructure carefully.Awaitedand thenable detection — any object with a.thenmethod is treated as a thenable. Real-world types (e.g.Bluebird<T>) work; oddly-shaped objects with a straythenfield can confuse it.NonNullable<T>and indexed-access —User["email"]whereemail?: stringisstring | undefined. Wrap withNonNullableto strip both, or useRequired<User>["email"].- Composing too many at once —
Required<Partial<Pick<Omit<T, "id">, "name" | "email">>>is hard to read. Extract intermediate aliases for clarity.
Real-world recipes
Recipe 1 — REST PATCH payload with required server-side fields excluded
Omit + Partial is the canonical shape for "any subset of editable fields." The server controls id/createdAt, so the client cannot send them.
interface UserRow {
id: number;
createdAt: Date;
name: string;
email: string;
bio?: string;
}
type UserPatch = Partial<Omit<UserRow, "id" | "createdAt">>;
async function patchUser(id: number, body: UserPatch): Promise<void> {
await fetch(`/users/${id}`, { method: "PATCH", body: JSON.stringify(body) });
}
await patchUser(1, { bio: "engineer" }); // OK
// await patchUser(1, { id: 2 }); // Error — id is excluded
Recipe 2 — Discriminated extraction with Extract
When you have a discriminated union and you want the specific variant for one kind, Extract does it in one line — no manual narrowing function required.
type ApiResult =
| { status: "ok"; data: string }
| { status: "loading" }
| { status: "error"; code: number; message: string };
type ErrorOnly = Extract<ApiResult, { status: "error" }>;
// { status: "error"; code: number; message: string }
function handleError(r: ErrorOnly): string {
return `[${r.code}] ${r.message}`;
}
console.log(handleError({ status: "error", code: 500, message: "boom" }));
Output:
[500] boom
Recipe 3 — Lookup map from a literal union with Record
A Record<UnionLiteral, V> keyed on as const data gives you both type-checked keys and exhaustiveness — adding a new union member fails to compile until the map is updated.
type Status = "draft" | "published" | "archived";
const COLOR: Record<Status, string> = {
draft: "#888",
published: "#0a0",
archived: "#a00",
};
function pill(s: Status): string {
return `<span style="color:${COLOR[s]}">${s}</span>`;
}
console.log(pill("published"));
Output:
<span style="color:#0a0">published</span>
Recipe 4 — Forwarding a function signature with Parameters/ReturnType
A "logging wrapper" preserves both arguments and return type without naming them — invaluable for middleware patterns.
function withLogging<F extends (...args: any[]) => any>(label: string, fn: F): F {
return ((...args: Parameters<F>): ReturnType<F> => {
console.log(`[${label}]`, args);
return fn(...args);
}) as F;
}
const add = (a: number, b: number) => a + b;
const loggedAdd = withLogging("add", add);
console.log(loggedAdd(2, 3));
Output:
[add] [ 2, 3 ]
5
Recipe 5 — Generic instantiator with ConstructorParameters/InstanceType
A factory accepts any class and the right arguments, returning a correctly-typed instance — zero any, zero overloads.
function instantiate<C extends abstract new (...args: any) => any>(
cls: C,
...args: ConstructorParameters<C>
): InstanceType<C> {
return new (cls as any)(...args);
}
class Logger { constructor(public name: string, public level: "info" | "warn") {} }
class Cache { constructor(public ttlMs: number) {} }
const log = instantiate(Logger, "api", "warn"); // Logger
const cache = instantiate(Cache, 60_000); // Cache
console.log(log.name, cache.ttlMs);
Output:
api 60000
Recipe 6 — Branded literal map with Record + Capitalize
Generate route handler names from an event union, ensuring every event has a handler and that handler names follow a strict pattern.
type Event = "click" | "focus" | "blur";
type HandlerName = `on${Capitalize<Event>}`;
type Handlers = Record<HandlerName, (e: globalThis.Event) => void>;
const handlers: Handlers = {
onClick: () => console.log("click"),
onFocus: () => console.log("focus"),
onBlur: () => console.log("blur"),
};
handlers.onClick(new Event("click"));
Output:
click
Recipe 7 — Pick + Partial + Required composition
Sometimes you want "these fields required, those optional, and nothing else allowed" — an exact PATCH shape.
interface Form {
email: string;
password: string;
bio?: string;
marketing?: boolean;
}
type SignupSubmit =
Required<Pick<Form, "email" | "password">> &
Partial<Pick<Form, "bio" | "marketing">>;
const f: SignupSubmit = { email: "a@b.c", password: "secret123" };
const g: SignupSubmit = { email: "a@b.c", password: "secret123", bio: "hi" };
console.log(f, g);
Output:
{ email: 'a@b.c', password: 'secret123' } { email: 'a@b.c', password: 'secret123', bio: 'hi' }
Recipe 8 — Awaited over a chain of fetchers
When function composition yields nested promises, Awaited<ReturnType<...>> extracts the final settled value.
async function login(): Promise<{ token: string }> { return { token: "abc" }; }
async function profile(_t: string): Promise<Promise<{ name: string }>> {
return Promise.resolve({ name: "Alice" });
}
type LoginResult = Awaited<ReturnType<typeof login>>; // { token: string }
type ProfileResult = Awaited<ReturnType<typeof profile>>; // { name: string }
async function loginAndFetch(): Promise<ProfileResult> {
const { token } = await login();
return profile(token);
}
console.log(await loginAndFetch());
Output:
{ name: 'Alice' }
Quick reference table
| Utility | Input | Output |
|---|---|---|
Partial<T> | { a: string } | { a?: string } |
Required<T> | { a?: string } | { a: string } |
Readonly<T> | { a: string } | { readonly a: string } |
Record<K, V> | "x"|"y", number | { x: number; y: number } |
Pick<T, K> | User, "id"|"name" | { id: number; name: string } |
Omit<T, K> | User, "id" | User without id |
Exclude<T, U> | string|null, null | string |
Extract<T, U> | string|number, string | string |
NonNullable<T> | string|null|undefined | string |
ReturnType<T> | () => number | number |
Parameters<T> | (a: string) => void | [a: string] |
ConstructorParameters<T> | typeof MyClass | constructor params tuple |
InstanceType<T> | typeof MyClass | MyClass |
Awaited<T> | Promise<string> | string |
Uppercase<S> | "hello" | "HELLO" |