Skip to content
TypeScript types · Core · about 15 minutes

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.

  1. Hint 1

    infer names a part of the type you match against: F extends (...args: any[]) => infer R ? R : never.

  2. 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.