Want a faster signal before interviews? Take the Interview Ready Check →

DAY 16 OF 30

Discriminated unions

Yesterday, in one sentence

What is a type guard in TypeScript? Give some examples.

Interview question

What is a type predicate, and why would you need one?

A discriminated union is a union typeUnion Type of object typesObject Type, where each one has a property with the same name and gives it a different literal typeLiteral Type. That shared property is called the discriminant.

type XMen = { kind: "mutant" }; // kind is the literal type "mutant"
type Shield = { kind: "human" }; // kind is the literal type "human"
type Asgardian = { kind: "asgardian" }; // kind is the literal type "asgardian"

type Character = XMen | Shield | Asgardian;

Checking the discriminant narrows the whole object, without needing in or a type predicate. The discriminant has to be a literal type. If kind were string, every object type would allow any string and TypeScript would have nothing to tell them apart with.

function describe(character: Character) {
  if (character.kind === "mutant") {
    character; // character is XMen here
  }

  if (character.kind === "human") {
    character; // character is Shield here
  }
}

You can read character.kind before narrowing because every object type in the union has it. A property that only exists on one of them would still need the in operator.

Check yourself

Why does this not narrow?
type Hero = { kind: string }
type Villain = { kind: string }

function act(character: Hero | Villain) {
  if (character.kind === "hero") {
    // ...do something
  }
}
What is a discriminated union in TypeScript?