TYPESCRIPT / CHAPTER 13

Conditional types and union distribution

Advanced

Reason about type transformations without confusing them with runtime branches.

By the end of this chapter

  • Read extends tests in conditional types
  • Predict distribution over unions
  • Use infer to extract relationships

The idea

A conditional type selects a type based on assignability, using T extends U ? X : Y. This is a compile-time transformation; it does not inspect runtime objects or generate a JavaScript if statement. infer can name part of a matched type, such as an array element type, so the output stays related to the input.

When the checked side is a naked type parameter, conditional types distribute over union members. That makes filters possible: a member mapped to never disappears from the resulting union. Wrapping both compared sides in tuples disables this per-member distribution and asks about the union as a whole. Work through each member separately before using a conditional type in a public API; concise syntax can hide an unexpectedly broad or empty result.

TypeScript example
type ElementOf<T> = T extends readonly (infer U)[] ? U : T;
type KeepText<T> = T extends string ? T : never;
const value: ElementOf<number[]> = 4;
const label: KeepText<"open" | 7 | "closed"> = "open";
console.log(value, label);
Result
4 open

ElementOf extracts number; the distributive filter retains only the two string literal members.

Try it yourself

Define a conditional type that extracts a promise’s result while leaving non-promises unchanged, then test union inputs.

Use your own editor for this exercise. Runnable challenges on CodeQuest are available for JavaScript, Python, and SQL.

CHECK YOUR UNDERSTANDING

Chapter checkpoint

What is KeepText<string | number> for type KeepText<T> = T extends string ? T : never?