Skip to content
webtype.orgTwelve concepts · 6/12

Concept 6 of 12

Conditional types

A conditional type is the type-level `if`. The question it asks is always the same one: is the left side assignable to the right? Not "are these equal", not "is this an instance of" — assignable, one direction only.

Assignability, not equality

type A = 'hello' extends string ? true : false   // true
type B = string extends 'hello' ? true : false   // false
type C = never extends string ? true : false     // true — never fits anywhere
type D = { a: 1; b: 2 } extends { a: 1 } ? true : false  // true

A narrower type is assignable to a wider one, so the test is directional. An object with extra properties is assignable to one with fewer, which is why `extends` cannot be used to check that two object types are the same shape.

When you genuinely need "the same type", you need the `Equal` helper every check on this site is built on — two deferred conditionals compared for identity, which is stricter than assignability in both directions.

Branches are tested in order

type Describe<T> = T extends (...args: never[]) => unknown
  ? 'function'
  : T extends unknown[]
    ? 'array'
    : T extends object
      ? 'object'
      : 'primitive'

Narrower cases have to come first. Functions and arrays are both objects, so testing `extends object` early would swallow them — the classic cause of a `DeepReadonly` that quietly destroys every function it touches.

The common wrong answer

// Intent: is T exactly string?
type IsString<T> = T extends string ? true : false

IsString<'hello'>  // true — but 'hello' is not string, it is narrower
IsString<any>      // boolean — any matches both branches at once

`extends` answers "fits into", so every string literal passes a test for `string`. And `any` is assignable to everything, so a conditional given `any` returns the union of both branches — a result that is almost never what the author intended.

Takeaway

Conditionals ask about assignability and test branches in order. Narrow first, and reach for `Equal` the moment you need actual sameness.

Practiced in