Lesson 16 / 25

Algebraic Data Types

Sum and product types, discriminated unions in TypeScript.

AND types and OR types

A product type combines several values at once: a record or tuple such as { x: number; y: number } holds an x and a y. A sum type is exactly one of several alternatives: a shape is a circle or a rectangle. Together they are algebraic data types (ADTs). Haskell, Rust, OCaml and Kotlin (sealed classes) have them built in. TypeScript models sum types as discriminated unions: each variant has a literal tag field such as kind, and the compiler narrows the type when you check it. ADTs let you make illegal states unrepresentable, for example a request that cannot be both loading and failed.

Making illegal states unrepresentable

Algebraic data types, pattern matching and Option/Result types model data precisely and force every case to be handled.

Three ideas: sum and product types, exhaustive matching, Option and Result.
Figure 6.1 — Types, matching and explicit absence or failure.

Replacing flags with a union

Booleans allow impossible combinations; a union does not.

// Before: 2 x 2 x optional fields allows nonsense states
type RequestStateLoose = {
  loading: boolean;
  error?: string;
  data?: string[];
};

// After: a sum type of product types
type RequestState =
  | { kind: 'idle' }
  | { kind: 'loading' }
  | { kind: 'failed'; error: string }
  | { kind: 'loaded'; data: string[] };

type Shape =
  | { kind: 'circle'; radius: number }
  | { kind: 'rect'; width: number; height: number };

The same type in Haskell

data Shape = Circle Double | Rect Double Double declares a sum type with two constructors; each constructor holds a product of fields.

Quick check: What is a sum type?

  • A number type used for addition
  • A record that holds several fields at once
  • A value that is exactly one of several tagged alternatives
  • A list of all possible values
Answer

A value that is exactly one of several tagged alternatives — Sum = OR, product = AND.