Conditional types using infer

Infer keyword in Typescript

It is used in conditional type resolution.

type MultipleInfers<T> = T extends { a: infer U, b: infer U, c: infer U } ? U : never;

type Tstring = MultipleInfers<{a: string, b: string, c: string}>;
type Tstring_or_number = MultipleInfers<{a: string, b: number, c: string}>;


const str: Tstring = "Hello world"; // type of str is just string 
const str_or_number: Tstring_or_number = 2; // type of str_or_number is string | number 

As you might already seen, infer U accumulates all the types and them resolves them to a new type U.

Let’s move on and take a look at a more advanced usage of infer where we are going to resolve a type from a function parameter:

type Func<P, R> = (
  param: P
) => R;

type FuncArg<
  F extends Func<any, any>
> = F extends Func<infer P, any> ? P : never;

const myFunction = (x: number ): string => {
  return "OK";
};

const paramType: FuncArg<typeof myFunction> = 2;

Breaking down the above example:

Define a function type which will have 1 param

type Func<P, R> = (
  param: P
) => R;

This will enable us to use it in the folowing way:
const func: Func<string, number> = (param: string): number => 2;

Next steps is defining the interface for function asignment:

type FuncArgs<
  F extends Func<any, any>
> = F extends Func<infer P, any> ? P : never;

Define another FuncArgs type who will get the first param a value that extends Func<any, any> (we are not going to restrict a type, so we are going to just use any).
As a return we are using infer P to destruct the first param of the function.

Testing:

const myFunction = (x: number ): string => {
  return "OK";
};

const paramType: FuncArg<typeof myFunction> = 2;

In our case we have a function with an argument of type number and as a result our paramType will have a type number.

You can also play with this implementation and break it so you’ll get a better understanding of how infer works.

Bonus

If for example we want to infer to the return type of the function we have to do this:

type FuncArgs<
  F extends Func<any, any>
> = F extends Func<infer P, infer R> ? R : never;

After we’ll do this, our variables will have the type of our return functions.

Share This:

Get The Best Of All Posts Delivered To Your Inbox

Subscribe to our newsletter and stay updated.