Utility types cheatsheet.
Partial / Required
type User = { id: number; name: string; email?: string };
type PatchUser = Partial<User>; // all optional
type FullUser = Required<User>; // all required (email becomes string)
Readonly
type RoUser = Readonly<User>;
// { readonly id: number; readonly name: string; ... }
Shallow — for deep, write your own:
type DeepReadonly<T> = {
readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K];
};
Pick / Omit
type Public = Pick<User, "id" | "name">;
type NoEmail = Omit<User, "email">;
Pick includes keys; Omit excludes.
Record
type RoleMap = Record<"admin" | "user", boolean>;
// { admin: boolean; user: boolean }
type ById<T> = Record<string, T>;
Exclude / Extract
type Animal = "dog" | "cat" | "fish";
type Land = Exclude<Animal, "fish">; // "dog" | "cat"
type Aqua = Extract<Animal, "fish">; // "fish"
NonNullable
type T = string | number | null | undefined;
type Solid = NonNullable<T>; // string | number
ReturnType / Parameters
function f(a: string, b: number): boolean { return true; }
type R = ReturnType<typeof f>; // boolean
type P = Parameters<typeof f>; // [string, number]
const args: P = ["hi", 42];
f(...args);
ConstructorParameters / InstanceType
class C {
constructor(public name: string) {}
}
type Args = ConstructorParameters<typeof C>; // [string]
type Inst = InstanceType<typeof C>; // C
Awaited
type R = Awaited<Promise<Promise<string>>>; // string
Unwraps all nesting.
ThisParameterType / OmitThisParameter
function f(this: { x: number }, y: number) {}
type T = ThisParameterType<typeof f>; // { x: number }
type Bound = OmitThisParameter<typeof f>; // (y: number) => void
String manipulation types
type Up = Uppercase<"hello">; // "HELLO"
type Lo = Lowercase<"HELLO">; // "hello"
type Cap = Capitalize<"hello">; // "Hello"
type Un = Uncapitalize<"HELLO">; // "hELLO"
Template literal types
type Event = "click" | "hover";
type Handler = `on${Capitalize<Event>}`; // "onClick" | "onHover"
type Path = `/users/${number}`;
const p: Path = `/users/${42}`;
Useful combinations
Partial + required keys
type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
type X = PartialBy<User, "email">; // email optional, others required
Required + optional keys
type RequiredBy<T, K extends keyof T> = Omit<T, K> & Required<Pick<T, K>>;
Pick by value type
type PickByValue<T, V> = {
[K in keyof T as T[K] extends V ? K : never]: T[K]
};
type StringFields = PickByValue<User, string>; // { name: string }
Deep partial
type DeepPartial<T> = {
[K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
};
Mutable (strip readonly)
type Mutable<T> = { -readonly [K in keyof T]: T[K] };
Required keys only
type RequiredKeys<T> = {
[K in keyof T]-?: {} extends Pick<T, K> ? never : K
}[keyof T];
Symmetric difference
type Diff<A, B> = Exclude<A, B> | Exclude<B, A>;
Common mistakes
Omit<T, K>doesn’t enforce K is a real key (for unions). UseOmit<T, K & keyof T>if you want strictness.Partialis shallow. Nested objects retain required keys.Record<string, T>includes prototype keys — usenoUncheckedIndexedAccessso access returnsT | undefined.- Mixing
PickandOmit— pick the one that’s shorter to read. Requireddoesn’t recurse — make a DeepRequired if needed.
Read this next
If you want my utility-types extension library, it’s at rajpoot.dev .
Building something AI-, backend-, or data-heavy and want a second pair of eyes? I do consulting and freelance work — see my projects and ways to reach me at rajpoot.dev .