With infer
, the compiler ensures that you have declared all type variables explicitly:
type MyType<T> = T extends infer R ? R : never;
type T1 = MyType<{b: string}> // T1 is { b: string; }
Here we declare a new type variable R
in MyType
, which gets inferred from T
.
(Note, that infer
is always used within the extends
clause of a conditional type.)
Usage of undeclared type parameters now can result in a compile error:
type MyType2<T> = T extends R2 ? R2 : never; // error, R2 undeclared
Without infer
, the compiler wouldn't know, if you wanted to introduce an additional type variable R2
that is to be inferred (see first case), or if R2
is just an accidental typing error/typo. infer
exists to remove this ambiguity.
More precisely the compiler checks, if T
is assignable to R
, when infer
is omitted:
type R = { a: number }
type MyType3<T> = T extends R ? R : never; // compare T with type R
type T3 = MyType3<{b: string}> // T3 is never
Note, that infer R
shadows type references of an equally-named type declaration R
:
type R = { a: number }
type MyType4<T> = T extends infer R ? R : never;
type T4 = MyType4<{b: string}> // { b: string; }
Playground