TypeScript utility types
TypeScript ships helpers that transform existing types. They live in the standard library and compose with keyof, indexed access, and generics.
Partial, Required, Readonly
type User = { id: string; name: string; email: string };
// All keys optional — useful for PATCH payloads
type UserPatch = Partial<User>;
// Every key required (strip ?)
type Strict = Required<Partial<User>>;
// Shallow readonly — nested objects stay mutable unless you map them
type FrozenUser = Readonly<User>;
Partial and Readonly are shallow; nested objects keep their original mutability unless you map them yourself.
Pick and Omit
type User = { id: string; name: string; email: string; role: 'admin' | 'member' };
type PublicUser = Pick<User, 'id' | 'name'>;
type UserWithoutEmail = Omit<User, 'email'>;
// Common: props for a presentational component
type UserCardProps = Pick<User, 'name' | 'role'>;
Pick<T, K> keeps only keys K. Omit<T, K> removes keys K. With unions, Omit distributes over members.
Record<Keys, Value>
type Role = 'admin' | 'editor' | 'viewer';
const defaultCaps: Record<Role, boolean> = {
admin: true,
editor: true,
viewer: false,
};
// Same as { [K in Role]: boolean }
Use Record when every key in a union should map to the same value type.
ReturnType and Parameters
function createUser(name: string, role: 'admin' | 'member') {
return { id: crypto.randomUUID(), name, role };
}
type NewUser = ReturnType<typeof createUser>;
type CreateUserArgs = Parameters<typeof createUser>;
// [name: string, role: 'admin' | 'member']
Works with overloaded functions by using the last overload’s signature. For class instances, use InstanceType<typeof MyClass>.
Exclude, Extract, NonNullable
type T = 'a' | 'b' | 'c';
type NoA = Exclude<T, 'a'>; // 'b' | 'c'
type JustA = Extract<T, 'a' | 'z'>; // 'a'
type MaybeId = string | null | undefined;
type Id = NonNullable<MaybeId>; // string
Recipes
Update handler for a subset of keys
type User = { name: string; email: string; age: number };
function patchUser<K extends keyof User>(key: K, value: User[K]): Pick<User, K> {
return { [key]: value } as Pick<User, K>;
}
The as Pick<User, K> assertion satisfies the compiler for a single known key; it does not validate value at runtime.
Props except one key
type Props = { title: string; body: string; footnote?: string };
type HeaderOnly = Omit<Props, 'body' | 'footnote'>;
Nullable-to-optional for forms
type ApiUser = { id: string; nickname: string | null };
type FormUser = Omit<ApiUser, 'nickname'> & { nickname?: string };