/** * The Maybe monad, except that pure(undefined) returns Nothing, rather than * Just undefined. Also, we match js's convention from Promise of not requiring * the user's bind() argument to always return the monad (i.e., we merge bind * and map); if a raw value x is returned, it's converted to Maybe(x). * Note: normally Nothing would be a single value not a class, but making it * a class helps Typescript. */ export type Maybe = Just | Nothing; // tslint:disable max-classes-per-file export class Nothing { getOrDefault(defaultVal?: T): T | undefined { return defaultVal; } bind(transform: (v: T) => Maybe | U | undefined): Maybe { return this as any as Nothing; } map(transform: (v: T) => U | undefined): Maybe { return this as any as Nothing; } } export class Just { private val: T; constructor(x: T) { this.val = x; } getOrDefault(defaultVal?: T): T | undefined { return this.val; } map(transform: (v: T) => U | undefined): Maybe { return Maybe(transform(this.val)); } bind(transform: (v: T) => Maybe | U | undefined): Maybe { const transformed = transform(this.val); if(transformed instanceof Just || transformed instanceof Nothing) { return transformed; } else { return Maybe(transformed); } } } const NOTHING = new Nothing(); export default function Maybe(x: T | undefined): Maybe { // Sometimes, null is a valid value, so we only make undefined into Nothing. return x !== undefined ? new Just(x) : (NOTHING as Nothing); }