Chapter 7.6☕ 17 min read

infer Keyword

infer = "bhai, andar kya hai nikal ke bata!"

01The Undercover Detective

The infer keyword is used INSIDE conditional types to EXTRACT a type that's hidden inside another type. It's like saying "I don't know what type this is, but figure it out and give it a name so I can use it." Without infer, conditional types can only CHECK if a type matches a pattern. With infer, they can CAPTURE parts of that pattern and bring them into scope. This is what makes conditional types truly powerful.

Think of the undercover detective at the Hyderabad customs. A suspicious package arrives — you know it CONTAINS something, but you don't know WHAT. The detective opens the package, examines the contents carefully, and says "INFERRED: this contains gold biscuits!" The infer keyword is that detective — it peeks inside a type structure and names the hidden inner type.

T extends Promise<infer U> ? U : T — "If T is a Promise, figure out what type it resolves to and call it U. Then return U." The detective doesn't change the package — it just IDENTIFIES what's inside. infer can only be used in the extends clause of a conditional type — it can't exist on its own. It's a pattern-matching tool, not a standalone type declaration. Seedha samjho: infer = "bhai, andar kya hai nikal ke bata!" This single keyword unlocks some of the most advanced and useful type manipulations in TypeScript.

02infer Syntax & Basics

infer appears in the extends clause of a conditional type. The syntax is straightforward once you see it as a pattern-matching exercise: T extends SomeType<infer U> ? U : T. TypeScript checks if T matches the pattern, and if it does, it binds the matched part to the inferred name U.

Unwrapping Promises:

type UnwrapPromise<T> =
  T extends Promise<infer U>
    ? U
    : T;

type A = UnwrapPromise<Promise<string>>;
// A is string

type B = UnwrapPromise<number>;
// B is number (not a promise)

Unwrapping Arrays:

type UnwrapArray<T> =
  T extends Array<infer U>
    ? U
    : T;

type C = UnwrapArray<string[]>;
// C is string

Extracting Function Return Types:

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

type D = ReturnOf<() => number>;
// D is number

type E = ReturnOf<
  (x: string) => boolean
>;
// E is boolean

Extracting Function Parameter Types:

type FirstParam<T> =
  T extends (
    first: infer F,
    ...rest: any[]
  ) => any
    ? F
    : never;

type F = FirstParam<
  (x: string, y: number) => void
>;
// F is string

Each of these patterns follows the same structure: match a shape, use infer to name a hole in that shape, and then use the inferred name in the result.

03Real-World infer Patterns

Real-world TypeScript codebases use infer heavily, and TypeScript itself ships with several built-in utility types that rely on it. Understanding these patterns helps you read library code and write your own advanced type utilities.

1. ReturnType<F> — Built-in:

type R = ReturnType<typeof fetch>;
// The return type of fetch
// Promise<Response>

2. Parameters<F> — Built-in:

type P = Parameters<typeof fetch>;
// Tuple of fetch's parameter types
// [input: RequestInfo, init?: RequestInit]

3. Awaited<T> — Built-in (TS 4.5+):

type A = Awaited<
  Promise<Promise<string>>
>;
// A is string (recursively unwrapped!)

4. Extracting from Constructors:

type InstanceOf<C> =
  C extends new (
    ...args: any[]
  ) => infer I
    ? I
    : never;

type T = InstanceOf<typeof Date>;
// T is Date instance type

5. Multiple infer Positions:

type UnpackFn<T> =
  T extends (
    a: infer A,
    b: infer B
  ) => infer R
    ? { a: A; b: B; r: R }
    : never;

type X = UnpackFn<
  (x: string, y: number) => boolean
>;
// { a: string; b: number; r: boolean }

The infer keyword creates a BINDING — the inferred type is available in the true branch of the conditional. You can have multiple infer positions in a single conditional type, each capturing a different part of the pattern.

04infer Traps

The infer keyword is incredibly powerful, but it comes with traps that can confuse even experienced TypeScript developers. Let's walk through the most common mistakes so you can avoid them in your code.

Trap 1: infer outside conditional type

// ERROR! infer can't exist alone
type X = infer U;

// RIGHT: inside extends clause
type X<T> =
  T extends Promise<infer U>
    ? U
    : T;

infer can ONLY appear in the extends clause of a conditional type. It's not a standalone keyword — it only makes sense when TypeScript is pattern-matching against a structure.

Trap 2: Multiple infer with same name

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

// With { a: string, b: number }
// U = string & number = never!

If both a and b infer U, TypeScript INTERSECTS them! Use different names: infer A, infer B.

Trap 3: infer in the result branches

// ERROR! infer only in extends
type X<T> =
  T extends string
    ? infer U
    : never;

// RIGHT: infer in the condition
type X<T> =
  T extends Promise<infer U>
    ? U
    : never;

Trap 4: Nested genericsT extends Promise<Promise<infer U>> only unwraps TWO levels. For arbitrary nesting, use recursive conditional types like Awaited.

Trap 5: Extracting the wrong thingReturnType<(a: string) => void> gives void, not string! You extracted the RETURN type, not the parameter. Use Parameters for params.

05infer Keyword Cheatsheet

Here's your complete cheatsheet for the infer keyword. Pin this to your mental whiteboard — it's the key to unlocking advanced type-level programming in TypeScript.

Syntax:

T extends SomeType<infer U>
  ? U
  : Fallback;

Common Patterns:

// Unwrap Promise
Promise<infer U>

// Unwrap Array
Array<infer U>

// Function return type
(...args: any[]) => infer R

// Function first param
(first: infer F, ...rest: any[]) => any

// Constructor instance
new (...args: any[]) => infer I

Built-ins Using infer:

  • ReturnType<T> — function return type
  • Parameters<T> — function params as tuple
  • Awaited<T> — recursive Promise unwrap
  • InstanceType<T> — constructor instance

Key Rules:

  • infer = "andar kya hai nikal ke bata"
  • Only works inside conditional type extends clause
  • Multiple same-name infer = intersection
  • Use different names for different positions
  • Combine with recursion for deep unwrapping

The Golden Rule: infer is the undercover detective — it peeks inside types and names what it finds. Use it wisely, bhai, and it'll crack any type case!

Key Points

  • infer extracts hidden types from inside other types — like a detective opening a package
  • infer can ONLY be used in the extends clause of a conditional type
  • Common patterns: unwrap Promise, Array, extract function return/params
  • Multiple infer with the same name creates an intersection of all inferred types
  • TypeScript built-ins like ReturnType, Parameters, and Awaited all use infer under the hood
Course Search
Search across all chapters & stages
📖

Search the course

Type any topic — branching, stash, rebase, hooks — and jump straight to that chapter.

merge branchesgit stashundo commitrebase