Algebraic data types are a way of representing data by combining simple types using algebraic operations. There are two main kinds of algebraic types: product types and sum types. Discriminated unions are a specific implementation of sum types.
Product types represent a combination of types.
type Shirt = {
size: string
sleeveLength: string
shape: string
}
Sum types represent a choice between types.
type ShirtSize = "S" | "M" | "L" | "XL" | "XXL"
type SleeveLength = "Short" | "Long"
Compose small types from other small types.
type SleeveLength = "Short" | "Long"
type Shirt = {
size: "S" | "M" | "L" | "XL" | "XXL"
sleeveLength: SleeveLength
shape: string
}
It's possible by adding a "kind" field to the product type.
type SleeveLength = "Short" | "Long"
type Shirt = {
kind: "Shirt"
size: "S" | "M" | "L" | "XL" | "XXL"
sleeveLength: SleeveLength
shape: string
}
type Jean = {
kind: "Jean"
hipSize: number
legSize: number
...
}
type Clothing = Shirt | Jean
const clothing: Clothing = {
kind: "Shirt",
size: "L",
sleeveLength: "Short",
shape: "Straight",
}
const describeClothing = (clothing: Clothing) => {
switch (clothing.kind) {
case "Shirt": return "This is a shirt!"
case "Jean": return "This is a jean!"
}
}
You can go further by adding sections to kinds in order to combine Clothing and Shoes.
kind: "Clothing/Shirt"
kind: "Clothing/Jean"
kind: "Shoes/Sneakers"
kind: "Shoes/Boots"
type Product = {
id: number
price: Price
item: Clothing | Shoes
}
In OpenAPI specification, sum types are represented by oneOf
.
Clothing:
oneOf:
- $ref: "#/components/schemas/Shirt"
- $ref: "#/components/schemas/Jean"
discriminator:
propertyName: kind
mapping:
Shirt: "#/components/schemas/Shirt"
Jean: "#/components/schemas/Jean"