TypeScript · Types that pay for themselves

How do conditional types work?

Hardconditional-typesdistributivetype-systemUpdated Oct 2026
Quiz this track

Short answer

A conditional type chooses between two types based on whether one type extends another. When the checked type is a naked type parameter, the condition distributes over unions.

A conditional type has the form T extends U ? X : Y. It is a type-level if. The compiler checks assignability: if T is assignable to U, the result is X; otherwise it is Y. Conditional types are the foundation of utility types such as Exclude and Extract.

ts
type IsString<T> = T extends string ? true : false;

type A = IsString<"x">;
type B = IsString<number>;

type ToArray<T> = T extends unknown ? T[] : never;
type Result = ToArray<string | number>;
Result is string[] | number[] because the naked type parameter distributes over the union.

Distribution and its escape hatch

  • A naked type parameter distributes over each member of a union
  • Wrapping both sides in tuples stops distribution
  • Distributive conditionals are how Exclude and Extract filter unions
  • Conditional types are lazy until the type arguments are known
  • Nested conditionals can model more than two branches
ts
type IsUnion<T> =
  [T] extends [infer U]
    ? ([U] extends [T] ? false : true)
    : false;
The tuple wrapper prevents the check from distributing, so the whole union is compared at once.
Conditional types can become unreadable quickly. Name intermediate types and test them with type-level assertions rather than debugging a deeply nested expression.

Follow-ups you should expect

Interviewers use these to check whether the first answer was understanding or memorisation.

  1. 1What does it mean for a conditional type to distribute?
  2. 2How do you prevent distribution?
  3. 3How are Exclude and Extract implemented?
  4. 4When is a conditional type evaluated?

Say it in the interview

A conditional type picks one of two branches based on whether a type extends another. When the checked type is a naked type parameter and the input is a union, the condition distributes over each member. That is how utility types like Exclude work. If I need to compare whole unions instead, I wrap both sides in tuples to stop distribution.

Use this as a model, not a script. Saying it in your own words is what makes it survive follow-up pressure.

Related questions

Reading is step one

Now say it out loud.

Understanding an answer and delivering it under pressure are different skills. Rehearse this topic in a live TypeScript mock interview and get scored feedback on depth, clarity and confidence.