Skip to content
Skip to content
DocsTypeScript ExpertexpertThe infer Keyword
Chapter 5 of 10·expert·8 min read

The infer Keyword

Từ Khoá infer

Extract and name types from within conditional type branches

Hover or tap any paragraph to see Vietnamese translation

What Is the infer Keyword?

The infer keyword can only appear inside the condition of a conditional type. It instructs TypeScript to infer — extract — a type from that position and bind it to a local type variable that you can reference in the true branch.

infer-basics.ts
1// Without infer you can only check a type, not capture part of it.2// With infer you capture and name an inner type on the fly.34type Unwrap<T> = T extends Promise<infer Inner> ? Inner : T;56type A = Unwrap<Promise<string>>;  // string7type B = Unwrap<number>;           // number (falls through to false branch)

The variable Inner exists only within the true branch scope. TypeScript determines its type by solving what Inner must be for the condition T extends Promise<Inner> to hold.

Inferring Return Types

The most canonical use of infer is extracting a function's return type — this is exactly how the built-in ReturnType<T> is constructed.

return-type.ts
1// Built-in equivalent — implemented with infer2type MyReturnType<T extends (...args: unknown[]) => unknown> =3  T extends (...args: unknown[]) => infer R ? R : never;45function greet(name: string): string {6  return `Hello, ${name}`;7}89async function fetchUser(id: number): Promise<{ id: number; name: string }> {10  return { id, name: "Alice" };11}1213type GreetReturn  = MyReturnType<typeof greet>;      // string14type FetchReturn  = MyReturnType<typeof fetchUser>;  // Promise<{ id: number; name: string }>1516// Combine with Awaited to unwrap the Promise too17type ResolvedUser = Awaited<MyReturnType<typeof fetchUser>>;18// { id: number; name: string }

Inferring Parameter Types

You can equally extract a function's parameter types. The standard library ships Parameters<T>, but you can build specialised variants yourself.

parameter-types.ts
1// Built-in equivalent2type MyParameters<T extends (...args: unknown[]) => unknown> =3  T extends (...args: infer P) => unknown ? P : never;45// Extract only the first parameter6type FirstParameter<T extends (...args: unknown[]) => unknown> =7  T extends (first: infer F, ...rest: unknown[]) => unknown ? F : never;89// Extract the last parameter10type LastParameter<T extends (...args: unknown[]) => unknown> =11  T extends (...args: [...infer _, last: infer L]) => unknown ? L : never;1213function createUser(id: number, name: string, role: "admin" | "user") {}1415type AllParams   = MyParameters<typeof createUser>;    // [number, string, "admin" | "user"]16type First       = FirstParameter<typeof createUser>;  // number17type Last        = LastParameter<typeof createUser>;   // "admin" | "user"
Info
...infer _ is tuple rest inference — the underscore is a valid but discarded variable name. This is the standard technique for 'consuming' unwanted portions of a tuple.

Inferring from Arrays and Promises

infer is flexible with container types. You can extract an array's element type, a Promise's resolved value, or any generic type argument.

array-promise-infer.ts
1// Unwrap one level of array2type UnpackArray<T> = T extends (infer Item)[] ? Item : T;34// Recursively unwrap nested arrays5type DeepUnpackArray<T> = T extends (infer Item)[]6  ? DeepUnpackArray<Item>7  : T;89// Built-in Awaited<T> — simplified version10type MyAwaited<T> = T extends PromiseLike<infer Resolved>11  ? MyAwaited<Resolved>12  : T;1314type A = UnpackArray<string[]>;              // string15type B = UnpackArray<number[][]>;            // number[]  (one level)16type C = DeepUnpackArray<number[][][]>;      // number    (fully unwrapped)17type D = MyAwaited<Promise<Promise<Date>>>;  // Date

Inferring from Template Literals

TypeScript 4.5+ allows infer inside template literal types, enabling string-level parsing at the type layer.

template-literal-infer.ts
1// Extract the route method prefix: "GET /users" → "GET"2type ExtractMethod<T extends string> =3  T extends `${infer Method} ${string}` ? Method : never;45// Split a dot-separated path: "a.b.c" → ["a", "b.c"] heads6type Head<T extends string> =7  T extends `${infer H}.${string}` ? H : T;89type Tail<T extends string> =10  T extends `${string}.${infer T}` ? T : never;1112// Extract event name from "on<Event>" pattern13type EventName<T extends string> =14  T extends `on${infer E}` ? Uncapitalize<E> : never;1516type M  = ExtractMethod<"GET /users">;     // "GET"17type H  = Head<"user.profile.avatar">;     // "user"18type TL = Tail<"user.profile.avatar">;     // "profile.avatar"19type E  = EventName<"onClick">;            // "click"20type E2 = EventName<"onMouseEnter">;       // "mouseEnter"

Multiple infer in One Conditional

A single conditional type can contain multiple infer variables simultaneously, letting you extract several parts of a complex type in one step.

multiple-infer.ts
1// Swap the first and second argument of a two-argument function2type SwapArgs<T extends (a: unknown, b: unknown) => unknown> =3  T extends (a: infer A, b: infer B) => infer R4    ? (a: B, b: A) => R5    : never;67// Extract key and value types from a Map8type MapKV<T> = T extends Map<infer K, infer V>9  ? { key: K; value: V }10  : never;1112// Destructure a Promise-returning function into its parts
Info
When the same infer variable appears at both covariant and contravariant positions, TypeScript intersects or unions the inferred types depending on variance. Use distinct variable names if you want independent captures.

Summary

  • infer is only valid inside the condition clause of a conditional type
  • It names a portion of the type so you can reference it in the true branch
  • ReturnType, Parameters, and Awaited in the standard library are all built with infer
  • You can use multiple infer variables in one conditional to extract several parts at once
  • Template literal inference enables string-level parsing at the type layer
  • Recursive conditional types with infer handle arbitrarily nested container types
  • Built: 6/25/2026, 3:03:36 PM