Infer keyword

2 snippets in TypeScript

TSTypeScript

Generics with Conditional Types

TS · Generics
syntax
type Name<T> = T extends Condition ? TrueType : FalseType;
example
type IsArray<T> = T extends any[] ? true : false;

type Test1 = IsArray<string[]>;  // true
type Test2 = IsArray<number>;    // false

// Extracting element types
type ElementOf<T> = T extends (infer E)[] ? E : never;

type StrEl = ElementOf<string[]>;      // string
type NumEl = ElementOf<number[]>;      // number
type NoEl = ElementOf<boolean>;        // never
output
// Conditional types act like type-level if/else

Note When a conditional type receives a union as T, it distributes — the condition is applied to each union member independently. To prevent distribution, wrap both sides in brackets: [T] extends [Condition].

infer Keyword

TS · Advanced Types
syntax
type Result = T extends Pattern<infer U> ? U : Fallback;
example
// Extract the resolved type from a Promise
type UnwrapPromise<T> = T extends Promise<infer R> ? R : T;

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

// Extract function first argument
type FirstArg<T> = T extends (first: infer F, ...rest: any[]) => any ? F : never;

type FA = FirstArg<(name: string, age: number) => void>;  // string

// Extract array element type
type ArrayItem<T> = T extends readonly (infer E)[] ? E : never;
type Item = ArrayItem<readonly ["a", "b", "c"]>;  // "a" | "b" | "c"
output
// infer declares a type variable that TypeScript figures out from context

Note infer can only be used inside the extends clause of a conditional type. It captures whatever type fits in that position. Multiple infer clauses in the same conditional are allowed. In union position, infer produces a union; in intersection position (like function params), it produces an intersection.