import { Err, MapOption, None, Ok, Option, OptionCombinators, OptionMapOption, OptionMapOrElse, OptionMapResult, OptionPromise, OptionValue, Result, ResultPromise, Some, UnwrapableOption, } from "./mod"; const OptionType = { Some: Symbol(":some"), None: Symbol(":none"), }; export class SomeValue implements UnwrapableOption { value: T; constructor(value: T) { this.value = value; } [Symbol.iterator](): IterableIterator { return [this.value][Symbol.iterator](); } get type(): symbol { return OptionType.Some; } and(optb: Option): Option { return optb; } andThen(fn: (some: T) => OptionPromise): OptionPromise; andThen(fn: (some: T) => Promise>): OptionPromise; andThen(fn: (some: T) => Option): Option; andThen( fn: (some: T) => Option | OptionPromise | Promise>, ): OptionPromise | Option { const alt = fn(this.value); return alt instanceof Promise ? Some(alt) : alt; } filter(predicate: (some: T) => boolean): Option { return OptionValue.from( predicate(this.value) ? this : new NoneValue(), ); } flatten(this: Option): Option; flatten(this: Option>): Option; flatten(this: Option | Option>): Option { type Unwrap = { value: unknown }; const inner = (this as unknown as Unwrap).value; if (inner instanceof OptionValue) { return inner as unknown as Option; } else return OptionValue.from(this as unknown as SomeValue); } isSome(): boolean { return true; } isNone(): boolean { return false; } /** * Maps an Option to Option by applying a function to a contained value. */ map( fn: (some: T) => U, ): MapOption { const newVal = fn(this.value); return (newVal instanceof Promise ? Some(newVal.then(Some)) : Some(newVal)) as MapOption; } mapOption( _: () => U, fn: (some: T) => U, ): OptionMapOption { const rv = fn(this.value); return (rv instanceof Promise ? Some(rv as Promise>) : rv) as OptionMapOption; } mapResult(_: () => U, fn: (some: T) => U): OptionMapResult { const rv = fn(this.value); return (rv instanceof Promise ? Ok(rv as Promise>) : rv) as OptionMapResult; } mapOrElse( _: () => U, fn: (some: T) => U, ): OptionMapOrElse { return fn(this.value) as OptionMapOrElse; } okOr(_: E): Result { return Ok(this.value) as Result; } okOrElse(fn: () => Promise): ResultPromise; okOrElse(fn: () => E): Result; okOrElse(_: unknown): ResultPromise | Result { return Ok(this.value) as Result; } or(_: Option): Option { return OptionValue.from(this); } orElse(fn: () => Promise>): OptionPromise; orElse(fn: () => Option): Option; orElse( _: () => Option | Promise>, ): OptionPromise | Option { return OptionValue.from(this); } unwrap(): T { return this.value; } unwrapOr(_: T): T { return this.value; } unwrapOrElse(def: () => T): T; unwrapOrElse(def: () => Promise): T | Promise; unwrapOrElse(_: unknown): T { return this.value; } xor(optb: Option): Option { if (optb.isNone()) return OptionValue.from(this); else return None(); } } export class NoneValue implements OptionCombinators, UnwrapableOption { constructor() {} [Symbol.iterator](): IterableIterator { return [][Symbol.iterator](); } isSome(): boolean { return false; } isNone(): boolean { return true; } map( _: (val: T) => U, ): MapOption { return OptionValue.from(this as unknown as NoneValue) as MapOption; } mapOption( def: () => U, _: (some: T) => U, ): OptionMapOption { const rv = def(); return (rv instanceof Promise ? Some(rv as Promise>) : rv) as OptionMapOption; } mapResult(def: () => U, _: (some: T) => U): OptionMapResult { const rv = def(); return (rv instanceof Promise ? Ok(rv as Promise>) : rv) as OptionMapResult; } mapOrElse( def: () => U, _: (some: T) => U, ): OptionMapOrElse { return def() as OptionMapOrElse; } andThen(fn: (some: T) => OptionPromise): OptionPromise; andThen(fn: (some: T) => Promise>): OptionPromise; andThen(fn: (some: T) => Option): Option; andThen( _: (some: T) => Option | Promise>, ): OptionPromise | Option { return OptionValue.from(this as unknown as NoneValue); } okOr(err: E): Result { return Err(err) as Result; } okOrElse(fn: () => Promise): ResultPromise; okOrElse(fn: () => E): Result; okOrElse(fn: () => Promise | E): ResultPromise | Result { const err = fn(); return err instanceof Promise ? Err(err) as ResultPromise : Err(err) as Result; } or(optb: Option): Option { return optb; } orElse(fn: () => Promise>): OptionPromise; orElse(fn: () => Option): Option; orElse( fn: () => Option | Promise>, ): OptionPromise | Option { const alt = fn(); return alt instanceof Promise ? Some(alt) : alt; } and(_: Option): Option { return OptionValue.from(this as unknown as NoneValue); } filter(_: (some: T) => boolean): Option { return OptionValue.from(this); } flatten(this: Option): Option; flatten(this: Option>): Option; flatten(this: Option | Option>): Option { return OptionValue.from(this as unknown as NoneValue); } unwrap(): T { throw new Error("Cannot unwrap None"); } unwrapOr(def: T): T { return def; } unwrapOrElse(def: () => T): T; unwrapOrElse(def: () => Promise): T | Promise; unwrapOrElse(def: () => Promise | T): T | Promise { return def(); } xor(optb: Option): Option { return optb; } get type(): symbol { return OptionType.None; } }