Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Algebraic Data Types in TypeScript
// Types:
type Just<T> = { Just: T }
type Nothing = {}
type Maybe<T> = Just<T> | Nothing
type Left<L> = { Left: L }
type Right<R> = { Right: R }
type Either<L, R> = Left<L> | Right<R>
// For convenience:
const Nothing: Nothing = {};
function Just<T>(x: T): Just<T> {
return { Just: x };
}
function Left<L>(x: L): Left<L> {
return { Left: x };
}
function Right<R>(x: R): Right<R> {
return { Right: x };
}
// Type guards:
function isJust<T>(x: Maybe<T>): x is Just<T> {
return "Just" in x;
}
function isLeft<L, R>(x: Either<L, R>): x is Left<L> {
return "Left" in x;
}
function isRight<L, R>(x: Either<L, R>): x is Right<R> {
return "Right" in x;
}
// Extraction functions:
function fromMaybe<T>(fallback: T, x: Maybe<T>): T {
return isJust(x) ? x.Just : fallback;
}
function fromEither<L, R, Y>(fl: (l: L) => Y, fr: (r: R) => Y, x: Either<L, R>): Y {
return isLeft(x) ? fl(x.Left) : fr(x.Right);
}
// Example values:
const aJust: Maybe<number> = Just(5);
const aNothing: Maybe<number> = Nothing;
const aLeft: Either<string, number> = Left("error");
const aRight: Either<string, number> = Right(100);
// Using the extraction functions:
const id = <T>(x: T) => x;
console.log(fromMaybe(0, aJust)); // 5
console.log(fromMaybe(0, aNothing)); // 0
console.log(fromEither(_ => 0, id, aLeft)); // 0
console.log(fromEither(_ => 0, id, aRight)); // 100
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment