Skip to content
intermediate Phase 7 · TypeScript

Union Types

Combine multiple types with union (|) and narrow with type guards.

30m
0 problems
Topic Progress 0%

Union Syntax

Union Syntax

Union types allow a value to be one of several types, using the | operator.

Basic Union

// A value can be string OR number
let id: string | number;

id = "abc123"; // OK
id = 123; // OK
// id = true; // Error!

Union with Literals

type Direction = "up" | "down" | "left" | "right";
type HttpMethod = "GET" | "POST" | "PUT" | "DELETE";

function move(direction: Direction): void {
  console.log(`Moving ${direction}`);
}

move("up"); // OK
// move("forward"); // Error!

Union of Object Types

type Success = {
  status: "success";
  data: string[];
};

type Error = {
  status: "error";
  message: string;
};

type Result = Success | Error;

function handleResult(result: Result) {
  if (result.status === "success") {
    console.log(result.data); // OK
  } else {
    console.log(result.message); // OK
  }
}

Function Parameters

function format(input: string | number): string {
  if (typeof input === "string") {
    return input.toUpperCase();
  } else {
    return input.toFixed(2);
  }
}

Type Narrowing

Type Narrowing

Type narrowing is the process of refining a union type to a more specific type using type guards.

typeof Guards

function process(value: string | number | boolean) {
  if (typeof value === "string") {
    // TypeScript knows value is string
    return value.toUpperCase();
  } else if (typeof value === "number") {
    // TypeScript knows value is number
    return value.toFixed(2);
  } else {
    // TypeScript knows value is boolean
    return value ? "yes" : "no";
  }
}

instanceof Guards

class Dog {
  bark() { return "Woof!"; }
}

class Cat {
  meow() { return "Meow!"; }
}

function makeSound(animal: Dog | Cat) {
  if (animal instanceof Dog) {
    return animal.bark();
  } else {
    return animal.meow();
  }
}

Truthiness Guards

function printName(name: string | null) {
  if (name) {
    // TypeScript knows name is string
    console.log(name.toUpperCase());
  }
}

'in' Operator

type Fish = { swim: () => void };
type Bird = { fly: () => void };

function move(animal: Fish | Bird) {
  if ("swim" in animal) {
    animal.swim();
  } else {
    animal.fly();
  }
}

Discriminated Unions

Discriminated Unions

Discriminated unions use a common property (discriminant) to distinguish between types.

Basic Pattern

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "rectangle"; width: number; height: number }
  | { kind: "triangle"; base: number; height: number };

function area(shape: Shape): number {
  switch (shape.kind) {
    case "circle":
      return Math.PI * shape.radius ** 2;
    case "rectangle":
      return shape.width * shape.height;
    case "triangle":
      return (shape.base * shape.height) / 2;
  }
}

Exhaustive Checking

function area(shape: Shape): number {
  switch (shape.kind) {
    case "circle":
      return Math.PI * shape.radius ** 2;
    case "rectangle":
      return shape.width * shape.height;
    case "triangle":
      return (shape.base * shape.height) / 2;
    default:
      const _exhaustive: never = shape;
      return _exhaustive;
  }
}

Real-World Example

type Action =
  | { type: "INCREMENT"; amount: number }
  | { type: "DECREMENT"; amount: number }
  | { type: "RESET" };

function reducer(state: number, action: Action): number {
  switch (action.type) {
    case "INCREMENT":
      return state + action.amount;
    case "DECREMENT":
      return state - action.amount;
    case "RESET":
      return 0;
  }
}

Quiz

1. What operator creates a union type?

Question 1 options

2. What is a discriminated union (specific to union types)?

Question 2 options

3. What is type narrowing?

Question 3 options

4. What does exhaustive checking ensure?

Question 4 options

Flashcards

Question

How do you create a union type?

Answer

Use the pipe operator: string | number

Question

What is a type guard?

Answer

An expression that checks the type at runtime

Question

What is a discriminated union?

Answer

A union with a common literal property for discrimination

Question

What is the never type used for in discriminated unions?

Answer

Exhaustive checking to ensure all cases are handled

Revision Notes

Key Takeaways

  • 1. Union types allow a value to be one of several types
  • 2. Type guards narrow types using typeof, instanceof, or in
  • 3. Discriminated unions use a common property to distinguish types
  • 4. Exhaustive checking ensures all union cases are handled
  • 5. Union types are powerful for modeling state

Interview Tips

  • Explain discriminated unions and their benefits
  • Show how type narrowing works with typeof and instanceof
  • Discuss exhaustive checking with the never type

Cheat Sheet

Cheat Sheet

Union Syntax

type ID = string | number;
type Status = "active" | "inactive";

Type Guards

if (typeof x === "string") { }
if (x instanceof Error) { }
if ("prop" in x) { }

Discriminated Unions

type Shape =
  | { kind: "circle"; radius: number }
  | { kind: "rect"; w: number; h: number };

switch (shape.kind) {
  case "circle": // ...
  case "rect": // ...
}

Exhaustive Check

default:
  const _: never = shape;
  return _;