C.W.K.
Stream
Lesson 06 of 07 · published

Conditional Types: `T extends X ? A : B`

~12 min · generics, conditional-types, type-computation

Level 0Curious
0 XP0/93 lessons0/23 achievements
0/100 XP to next level100 XP to go0% complete
"Type-level ternaries. The compiler computes types the way you compute values."

The shape

A conditional type has the form T extends X ? A : B. It evaluates at the type level: if T is assignable to X, the type is A; otherwise B. The extends here is the same structural-assignability check used in generic constraints.

Conditional types are how the standard library expresses computed types — ReturnType, Parameters, Awaited, NonNullable are all conditional types under the hood. Once you can read them, you can read most of TypeScript's advanced type library.

The distribution rule (preview)

When the checked type (the T) is a naked generic parameter, conditional types distribute over unions. type Wrap<T> = T extends unknown ? { value: T } : never applied to string | number distributes: Wrap<string> | Wrap<number> = { value: string } | { value: number }. We covered this in track 6; the same rule applies here.

The bracket trick ([T] extends [X]) disables distribution when you need it. Use this for yes/no checks where the union shouldn't be split.

Composing conditionals

You can chain conditionals: type Classify<T> = T extends string ? 'str' : T extends number ? 'num' : 'other'. Read like a multi-arm switch — each : T extends ... is the next case.

Conditional types are how you make types react to other types. They unlock most of the 'magic' people associate with advanced TypeScript — but they're just type-level ternaries, no more mysterious than that.

Code

Conditional types — checks and chains·typescript
// Basic conditional.
type IsString<T> = T extends string ? true : false;
type A = IsString<'hi'>;       // true
type B = IsString<42>;         // false

// Multi-arm chain.
type Classify<T> =
  T extends string ? 'str' :
  T extends number ? 'num' :
  T extends boolean ? 'bool' :
  'other';

type X = Classify<'hi'>;       // 'str'
type Y = Classify<true>;       // 'bool'
type Z = Classify<unknown[]>;  // 'other'

// Standard library style — ReturnType, simplified.
type MyReturnType<F> = F extends (...args: any[]) => infer R ? R : never;
type G = MyReturnType<() => string>;       // string
type H = MyReturnType<(x: number) => User>; // User

External links

Exercise

Write type ArrayElement<T> that returns the element type of T if T is an array, or T itself otherwise. ArrayElement<string[]> should be string; ArrayElement<number> should be number. Use the conditional type + infer pattern (preview of next lesson).
Hint
type ArrayElement<T> = T extends (infer E)[] ? E : T. The infer E captures the element type when T matches the array shape.

Progress

Progress is local-only — sign in to sync across devices.
Spotted a bug or have feedback on this page?Report an Issue

Comments 0

🔔 Reply notifications (sign in)
Sign inPlease sign in to comment.

No comments yet — be the first.