https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-inference-in-conditional-types
Type inference in conditional types Within the extends clause of a conditional type, it is now possible to have infer declarations that introduce a type variable to be inferred. Such inferred type variables may be referenced in the true branch of the conditional type. It is possible to have multiple infer locations for the same type variable.
For example, the following extracts the return type of a function type:
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any;
Conditional types can be nested to form a sequence of pattern matches that are evaluated in order:
type Unpacked<T> = T extends (infer U)[]
? U
: T extends (...args: any[]) => infer U
? U
: T extends Promise<infer U>
? U
: T;
type T0 = Unpacked<string>;
type T0 = string
type T1 = Unpacked<string[]>;
type T1 = string
type T2 = Unpacked<() => string>;
type T2 = string
type T3 = Unpacked<Promise<string>>;
type T3 = string
type T4 = Unpacked<Promise<string>[]>;
type T4 = Promise<string>
type T5 = Unpacked<Unpacked<Promise<string>[]>>;
type T5 = string
The following example demonstrates how multiple candidates for the same type variable in co-variant positions causes a union type to be inferred:
type Foo<T> = T extends { a: infer U; b: infer U } ? U : never;
type T1 = Foo<{ a: string; b: string }>;
type T1 = string
type T2 = Foo<{ a: string; b: number }>;
type T2 = string | number
Likewise, multiple candidates for the same type variable in contra-variant positions causes an intersection type to be inferred:
type Bar<T> = T extends { a: (x: infer U) => void; b: (x: infer U) => void }
? U
: never;
type T1 = Bar<{ a: (x: string) => void; b: (x: string) => void }>;
type T1 = string
type T2 = Bar<{ a: (x: string) => void; b: (x: number) => void }>;
type T2 = never
When inferring from a type with multiple call signatures (such as the type of an overloaded function), inferences are made from the last signature (which, presumably, is the most permissive catch-all case). It is not possible to perform overload resolution based on a list of argument types.
declare function foo(x: string): number;
declare function foo(x: number): string;
declare function foo(x: string | number): string | number;
type T1 = ReturnType<typeof foo>;
type T1 = string | number
It is not possible to use infer declarations in constraint clauses for regular type parameters:
type ReturnedType<T extends (...args: any[]) => infer R> = R;
'infer' declarations are only permitted in the 'extends' clause of a conditional type. Cannot find name 'R'.
type AnyFunction = (...args: any[]) => any;
type ReturnType<T extends AnyFunction> = T extends (...args: any[]) => infer R
? R
: any;