Last active
October 24, 2023 21:00
-
-
Save SimonAlling/fc1e779579d53378a5c1db1d31459118 to your computer and use it in GitHub Desktop.
Algebraic Data Types in TypeScript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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
I don't use this pattern anymore. Tagged unions are much more ergonomic, even if they may not be as syntactically pleasing. That is: