Utility types are ordinary generic aliases in lib.es5.d.ts, so each one is a mapped type, a conditional type, or infer:
type Partial<T> = { [P in keyof T]?: T[P] };
type Required<T> = { [P in keyof T]-?: T[P] };
type Readonly<T> = { readonly [P in keyof T]: T[P] };
type Pick<T, K extends keyof T> = { [P in K]: T[P] };
type Record<K extends keyof any, T> = { [P in K]: T };
type Exclude<T, U> = T extends U ? never : T;
type Extract<T, U> = T extends U ? T : never;
type Omit<T, K extends keyof any> = Pick<T, Exclude<keyof T, K>>;
type NonNullable<T> = T & {};
type Parameters<T extends (...args: any) => any> = T extends (...args: infer P) => any ? P : never;
type ReturnType<T extends (...args: any) => any> = T extends (...args: any) => infer R ? R : any;
(From the TS 5.9.3 source; NonNullable became T & {} in 4.8.)
What to say about them:
- Homomorphic ones keep modifiers.
PartialandReadonlyadd?/readonly;Requiredremoves?with-?.Pickkeeps the picked properties' modifiers. - All are shallow.
Partial<User>leavesaddressas a full object; for nested use a recursive type. Exclude/Extractfilter unions by distribution.Omitis not distributive.Omit's key type iskeyof any, so a typo such asOmit<User, "nope">compiles silently, whilePick<User, "nope">is an error.Record<string, T>is an index signature;Record<"a" | "b", T>is an object with exactly those keys.Awaited,InstanceType,ConstructorParametersfollow the sameinferpattern.
Use them to derive types from one source of truth: DTO variants, partial updates, component props minus a prop.