Important: This documentation covers Yarn 1 (Classic).
For Yarn 2+ docs and migration guide, see yarnpkg.com.

Package detail

@practical-fp/union-types

practical-fp13.8kMIT1.5.1TypeScript support: included

A Typescript library for creating discriminating union types.

adt, algebraic, discriminating, enum, sum, ts, type, typescript, union

readme

Union Types

NPM version badge Bundle size badge Dependency count badge Tree shaking support badge License badge

A Typescript library for creating discriminating union types. Requires Typescript 4.2 or higher.

Typescript Handbook on discriminating union types

Example

import { impl, Variant, match } from "@practical-fp/union-types"

type Shape =
    | Variant<"Circle", { radius: number }>
    | Variant<"Square", { sideLength: number }>

const { Circle, Square } = impl<Shape>()

function getArea(shape: Shape) {
    return match(shape)
        .with(Circle, ({ radius }) => Math.PI * radius ** 2)
        .with(Square, ({ sideLength }) => sideLength ** 2)
        .done()
}

const circle = Circle({ radius: 5 })
const area = getArea(circle)

Installation

$ npm install @practical-fp/union-types

Usage

Defining a discriminating union type

import { Variant } from "@practical-fp/union-types"

type Shape =
    | Variant<"Circle", { radius: number }>
    | Variant<"Square", { sideLength: number }>

This is equivalent to the following type:

type Shape =
    | { type: "Circle", value: { radius: number } }
    | { type: "Square", value: { sideLength: number } }

Creating an implementation

import { impl } from "@practical-fp/union-types"

const { Circle, Square } = impl<Shape>()

impl<>() can only be used if your environment has full support for Proxies.

Circle.is and Square.is can be used to check if a shape is a circle or a square. They also act as type guards.

const shapes: Shape[] = [circle, square]
const sideLengths = shapes.filter(Square.is).map(square => square.value.sideLength)

Generics

impl<>() also supports generic union types.

In case the variant type uses unconstrained generics, unknown needs to be passed as its type arguments.

import { impl, Variant } from "@practical-fp/union-types"

type Result<T, E> =
    | Variant<"Ok", T>
    | Variant<"Err", E>

const { Ok, Err } = impl<Result<unknown, unknown>>()

In case the variant type uses constrained generics, the constraint type needs to be passed as its type arguments.

import { impl, Variant } from "@practical-fp/union-types"

type Result<T extends object, E> =
    | Variant<"Ok", T>
    | Variant<"Err", E>

const { Ok, Err } = impl<Result<object, unknown>>()