infer

Pulls a type out from inside another type, within a conditional type.

On this page

Example

#
TypeScript
type ElementOf<T> = T extends (infer U)[] ? U : never
type Unwrap<T> = T extends Promise<infer U> ? U : T

type Tag = ElementOf<string[]>
// type Tag = string
type Data = Unwrap<Promise<{ level: number }>>
// type Data = { level: number }
type Plain = Unwrap<number>
// type Plain = number

const data: Data = { level: 7 }
console.log(data.level)
Result
7

Definition and usage

#

The infer keyword can only be used in the condition of a conditional type. It declares a new, local type parameter that TypeScript matches on its own. For example, T extends Promise<infer U> ? U : T pulls out the type of the value inside a promise.

That’s how the built-in utility types ReturnType, Parameters, and Awaited work. You can create your own: the type of an array element, the type of a callback’s argument, the type of a field in a nested object.

If the match fails, the conditional type falls through to the “false” branch, so it’s always worth thinking through what it should return in that case.

Syntax

#
Syntax
type Result<T> = T extends Pattern<infer U> ? U : Other

More examples

#
The type of a function’s first argument
TypeScript
type FirstArg<F> = F extends (first: infer A, ...rest: any[]) => any ? A : never

function greet(name: string, times: number) {
  return `Hi ${name}! `.repeat(times).trim()
}

type Name = FirstArg<typeof greet>
// type Name = string

const who: Name = 'Mia'
console.log(greet(who, 2))
Result
Hi Mia! Hi Mia!

Good practices

#
  • Before writing your own type with infer, check the built-in ones: ReturnType, Parameters, Awaited, InstanceType.
  • Name infer parameters descriptively when the type gets complex, e.g. infer TItem.

Related entries

#

Spotted a mistake or missing an example? Write to us.