Q20 of 38 · TypeScript

What are conditional types in TypeScript, and what is the `infer` keyword?

TypeScriptMidtypescriptconditional-typesinfergenericsadvanced-types

Short answer

Short answer: Conditional types use `T extends U ? X : Y` to produce a different type based on a condition. The `infer` keyword, used inside the extends clause, lets TypeScript extract and name a type from a matched position — the mechanism behind `ReturnType`, `Parameters`, and `Awaited`.

Detail

Conditional types are a form of type-level if-else. They evaluate at compile time to produce one type or another.

Basic form: T extends U ? TrueType : FalseType. If T is assignable to U, the result is TrueType; otherwise FalseType.

Distributive behaviour: When T is a union type and the conditional type is applied, TypeScript distributes the condition over each union member: string | number extends string ? "yes" : "no" produces "yes" | "no".

infer keyword: Inside the extends clause, infer K declares a type variable that TypeScript fills in by matching the structure. This is how built-in types extract nested types:

  • type ReturnType<F> = F extends (...args: any[]) => infer R ? R : never — extracts the return type
  • type Awaited<T> = T extends Promise<infer U> ? Awaited<U> : T — recursively unwraps

In test automation: Conditional types are used in advanced test helpers, fixture type utilities, and custom assertion type predicates. Understanding infer helps you read and debug complex type errors in Playwright's own type definitions.

// EXAMPLE

// Basic conditional
type IsString<T> = T extends string ? true : false;
type A = IsString<string>; // true
type B = IsString<number>; // false

// Distributive — over a union
type Flatten<T> = T extends Array<infer Item> ? Item : T;
type F1 = Flatten<string[]>;        // string
type F2 = Flatten<number[]>;        // number
type F3 = Flatten<string>;          // string (not array, return as-is)

// infer — extract type from structure
type UnpackPromise<T> = T extends Promise<infer U> ? U : T;
type P = UnpackPromise<Promise<string>>; // string
type Q = UnpackPromise<number>;          // number

// Practical: extract first param type
type FirstParam<F extends (...args: any[]) => any> =
  F extends (first: infer P, ...rest: any[]) => any ? P : never;

function greet(name: string, age: number) {}
type Name = FirstParam<typeof greet>; // string

// WHAT INTERVIEWERS LOOK FOR

The `T extends U ? X : Y` syntax and distributive behaviour. The `infer` keyword for type extraction — connecting it to built-in utilities like ReturnType and Awaited shows depth. Most mid-level candidates know conditional types exist; fewer can explain infer.

// COMMON PITFALL

Forgetting that conditional types with `infer` only work inside the `extends` clause — `infer` outside of a conditional extends is a syntax error.