infer is used inside a conditional type to capture (extract) a type from within another type into a new type variable you can then use. It's pattern-matching for types.
ts
<T> = T (infer U)[] ? U : ;
A = <[]>;
B = <[]>;
Read it as: "if T matches the pattern U[], bind U to whatever the element type is, and return it." The infer U declares a placeholder the compiler fills by matching.
// the resolved type of a Promise
type Awaited2<T> = T extends Promise<infer R> ? R : T;
type R = Awaited2<Promise<User>>; // User
// a function's return type (this is how ReturnType is built)
type MyReturn<T> = T extends (...args: any[]) => infer R ? R : never;
type X = MyReturn<() => number>; // number
// a function's first parameter
type FirstArg<T> = T extends (a: infer A, ...rest: any[]) => any ? A : never;
type UnwrapBoth<T> =
T extends Promise<infer U> ? UnwrapBoth<U> : // recurse to unwrap nested promises
T extends (infer E)[] ? E : T;
You can use several infers in one pattern and even recurse.
infer is the engine behind built-in types like ReturnType, Parameters, Awaited, and InstanceType, and behind library magic that derives response types from fetchers or props from components.
It lets type code "open up" a complex type and pull out the inner pieces — the most powerful tool for writing types that adapt to other types.