/** * Uso: * * const maybeNumber = Maybe.some(10); * const doubled = maybeNumber.map(n => n * 2); * console.log(doubled.getValue()); // 20 * const noValue = Maybe.none(); * console.log(noValue.isSome()); // false **/ export interface IMaybe { isSome(): boolean; isNone(): boolean; unwrap(): T; getOrUndefined(): T | undefined; map(fn: (value: T) => U): IMaybe; match(someFn: (value: T) => U, noneFn: () => U): U; } export class Maybe implements IMaybe { private constructor(private readonly value?: T) {} static fromNullable(value?: T): Maybe { return value === undefined || value === null ? Maybe.none() : Maybe.some(value); } static some(value: T): Maybe { return new Maybe(value); } static none(): Maybe { return new Maybe(); } isSome(): boolean { return this.value !== undefined; } isNone(): boolean { return !this.isSome(); } unwrap(): T { if (this.value === undefined || this.value === null) { throw new Error("Tried to unwrap a None value"); } return this.value; } getOrUndefined(): T | undefined { return this.unwrap(); } map(fn: (value: T) => U): Maybe { return this.isSome() ? Maybe.some(fn(this.value as T)) : Maybe.none(); } match(someFn: (value: T) => U, noneFn: () => U): U { return this.isSome() ? someFn(this.value as T) : noneFn(); } }