TYPESCRIPT

TypeScript Infer: Syntax, Usage, and Examples

The TypeScript infer keyword lets you extract and reuse types during conditional type evaluation. You can think of it as TypeScript's way of saying, “Figure out what this type is and give it a name I can use later.” The infer TypeScript feature shines when you’re building utility types, writing generic functions, or customizing type transformations.

How to Use Infer in TypeScript

You use the infer keyword inside a conditional type. It allows you to pull out part of a type and name it temporarily. Here's the basic syntax:

type InferSomething<T> = T extends SomeType<infer U> ? U : never;

In this example, if T matches SomeType<X>, then U becomes that X. If not, the result is never.

Let’s look at a simple real-world example using arrays:

type ElementType<T> = T extends (infer U)[] ? U : T;

type A = ElementType<string[]>; // string
type B = ElementType<number>;   // number

If T is an array, the infer keyword pulls out its item type. If it’s not, it just returns the type as is. That’s the core magic of infer in TypeScript_—it gives you dynamic type extraction while keeping everything safe and explicit.

When to Use Infer in TypeScript

You reach for TypeScript infer when:

  • You want to pull out a part of a more complex type (like an item from an array or a return type from a function).
  • You’re writing generic utility types.
  • You need to transform one type into another while preserving relationships.
  • You want your types to behave differently depending on the input shape.
  • You’re working with third-party types and need more flexibility.

You won’t use infer every day, but when you do, it can simplify even the most twisted type logic.

Examples of Infer TypeScript in Action

Infer a Function's Return Type

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

type MyFunction = () => string;
type Result = ReturnTypeOf<MyFunction>; // string

In this example, infer R pulls out the return type of a function. If T is a function, the conditional type returns its output type.

Infer from an Array

type FirstElement<T> = T extends [infer First, ...any[]] ? First : never;

type A = FirstElement<[number, string, boolean]>; // number
type B = FirstElement<[]>; // never

Here, infer pulls out the first element of a tuple. It's useful when analyzing structured data or form responses.

Infer a Promise's Resolved Type

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

type A = UnwrapPromise<Promise<number>>; // number
type B = UnwrapPromise<string>; // string

You can build powerful async-aware utilities this way. Whether you're handling API responses or chaining promises, infer simplifies the underlying types.

Infer Arguments from a Function

type Params<T> = T extends (...args: infer P) => any ? P : never;

type MyFunc = (a: string, b: number) => void;
type ArgTypes = Params<MyFunc>; // [string, number]

If you're building wrappers or decorators, this trick helps you extract argument types directly from the function signature.

Infer in Recursive Utility Types

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

type A = Flatten<number[][][]>; // number

This recursively pulls out the deepest type in a nested array. It’s great for working with JSON-like structures.

Learn More About Infer in TypeScript

How Infer Works Under the Hood

When TypeScript evaluates a conditional type with infer, it tries to match the left side to a pattern. If the match is successful, it binds the inferred type to the name you provide (U, T, etc.). If the match fails, the type falls back to whatever comes after the : in the conditional.

This makes infer in TypeScript behave a little like destructuring—but for types.

Combining Infer with Generics

Infer really shines inside generic utility types:

type Callback<T> = T extends (value: infer R) => void ? R : never;

type A = Callback<(x: boolean) => void>; // boolean

You’re not just inferring blindly—you’re tying inference to specific input types so your logic stays strong and reusable.

Narrowing Inferred Types

Once you infer a type, you can use it in additional conditional logic:

type DeepType<T> =
  T extends { nested: infer U }
    ? U extends { inner: infer V }
      ? V
      : never
    : never;

type A = DeepType<{ nested: { inner: string } }>; // string

This works like a step-by-step unpacking of nested structures.

Infer with Tuples and Rest Parameters

Tuples offer rich structures to explore with infer:

type Last<T extends any[]> = T extends [...any[], infer L] ? L : never;

type A = Last<[1, 2, 3]>; // 3

This infer example grabs the last element in a tuple.

You can also split and manipulate parameter lists:

type RemoveFirst<T extends any[]> = T extends [any, ...infer Rest] ? Rest : never;

type A = RemoveFirst<[string, number, boolean]>; // [number, boolean]

You’re not limited to objects or functions—infer works with arrays too.

Infer with Conditional Mapping

type ToString<T> = T extends number ? `${T}` : never;

type ID = ToString<123>; // "123"

This is technically not using infer, but often paired with it in type transformations where you create new string literal types based on inferred values.

Best Practices for Using Infer in TypeScript

  • Only use infer inside conditional types.
  • Name your inferred types clearly—avoid using single letters if they don’t convey intent.
  • Combine with generic constraints to keep your types readable and maintainable.
  • Use infer when existing utility types don't cover your case.
  • Don’t overuse infer. If a simpler approach works, go with that.
  • Always test inferred types using type aliases or utility checks in your IDE.

Common Patterns with TypeScript Infer

Building Your Own ReturnType

You don’t always need the built-in utility types. Here’s how you’d write your own:

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

This is exactly what TypeScript’s native ReturnType<T> does.

Conditional Behavior Based on Inferred Value

You can use infer to check how deep a type goes and respond accordingly:

type HasPromise<T> = T extends Promise<infer _> ? true : false;

type A = HasPromise<Promise<number>>; // true
type B = HasPromise<string>; // false

This makes it easy to write responsive utility types that adapt based on shape.

The TypeScript infer keyword gives you a tool for smart, reactive type transformations. Whether you're working with deeply nested arrays, composing generic utilities, or building libraries with flexible APIs, infer TypeScript capabilities help you write code that’s both safe and powerful. It may not be the first tool you reach for, but once you understand it, it becomes an essential part of your TypeScript toolkit.

Learn TypeScript for Free
Start learning now
button icon
To advance beyond this tutorial and learn TypeScript by doing, try the interactive experience of Mimo. Whether you're starting from scratch or brushing up your coding skills, Mimo helps you take your coding journey above and beyond.

Sign up or download Mimo from the App Store or Google Play to enhance your programming skills and prepare for a career in tech.

You can code, too.

© 2025 Mimo GmbH