Read types with infer
Write two types with infer. ReturnTypeOf<F> is the return type of a function type, and never for anything that is not a function. ElementOf<T> is the item type of an array or a readonly array, and never for anything else. Do not use the built-in ReturnType.
Start from
// The return type of a function type; never for anything else.
type ReturnTypeOf<F> = any;
// The item type of an array or readonly array; never for anything else.
type ElementOf<T> = any;Not allowed here, so the type is written by hand: ReturnType.
Hints
Each hint gives away a little more. Open one only when you need it.
Hint 1
infer names a part of the type you match against: F extends (...args: any[]) => infer R ? R : never.
Hint 2
readonly (infer U)[] matches both a readonly array and a normal array, because a normal array is assignable to a readonly one.
Solution
From here on the page gives the method away. If you are still solving, go back to the hints.
TypeScript
type ReturnTypeOf<F> = F extends (...args: any[]) => infer R ? R : never;
type ElementOf<T> = T extends readonly (infer U)[] ? U : never;The checks it must pass
type _1 = Expect<Equal<ReturnTypeOf<() => string>, string>>;
type _2 = Expect<Equal<ReturnTypeOf<(id: number) => Promise<{ id: number }>>, Promise<{ id: number }>>>;
type _3 = Expect<Equal<ReturnTypeOf<string>, never>>;
type _4 = Expect<Equal<ElementOf<number[]>, number>>;
type _5 = Expect<Equal<ElementOf<readonly ("a" | "b")[]>, "a" | "b">>;
type _6 = Expect<Equal<ElementOf<string>, never>>;What an interviewer looks for
infer is how you take a type apart: the result of an API function, the item of a list, the value inside a promise. It is the step from using types to writing them.