Skip to main content
  1. Posts/

TypeScript’s infer keyword: when generics aren't enough

·3 mins

If you’ve been using TypeScript for a while, you’re probably comfortable with generics. They let you write reusable types and functions. Pretty handy.

But sometimes generics hit a wall.

What if you want to extract the return type of a function? Or peel off the inner value of a Promise? Or get the second argument of a function type?

That’s where infer comes in.

What is infer? #

infer is a keyword you can use inside a conditional type to extract a piece of a type pattern.

The structure looks like this:

1
T extends SomePattern<infer U> ? U : Fallback

It reads like:

If T matches this pattern, grab the type inside as U. Otherwise, use Fallback.

It’s TypeScript’s way of saying:
“Try to deduce this type for me from the structure of something else.”

Example 1: Get the return type of a function #

Let’s say you have a function type:

1
type Fn = (name: string) => number;

You want to extract number from that.

Here’s how:

1
2
3
type Return<T> = T extends (...args: any[]) => infer R ? R : never;

type R = Return<Fn>; // R = number

Example 2: Recursively unwrap a deeply nested Promise #

Imagine this type:

1
type Nested = Promise<Promise<Promise<string>>>;

Want to get the string?

1
2
3
type DeepUnwrap<T> = T extends Promise<infer U> ? DeepUnwrap<U> : T;

type Final = DeepUnwrap<Nested>; // Final = string

Example 3: Get the second argument of a function #

Let’s say you’re building a middleware pipeline. You need to extract the res object from a handler type:

1
type Handler = (req: Request, res: Response, next: () => void) => void;

You want just the res.

1
2
3
type SecondArg<T> = T extends (a: any, b: infer B, ...args: any[]) => any ? B : never;

type Res = SecondArg<Handler>; // Res = Response

Example 4: Rebuild ReturnType<T> from scratch #

TypeScript’s built-in utility types (ReturnType, Parameters, etc.) use infer under the hood.

Here’s your own version of ReturnType:

1
type MyReturnType<T> = T extends (...args: any[]) => infer R ? R : never;

Same deal. You match a structure and pull out a piece.

Real-world use cases #

  • React HOCs: Extracting props from a component type.
  • API layers: Getting the shape of return data from an async call.
  • Function pipelines: Inferring argument or return types of composed functions.
  • Tooling: Libraries like ts-toolbelt, type-fest, and even Redux heavily rely on infer to keep types ergonomic.

Final thoughts #

infer is the kind of tool that separates day-to-day TypeScript use from serious type system wizardry.

If you’ve ever thought:

“There must be a way to extract just this part of the type…”

…there probably is. And it probably involves infer.