import { Result } from './result.js' enum OptionType { Some , None } export class Option { private constructor(type: OptionType.Some, value: T) private constructor(type: OptionType.None) private constructor(private type: OptionType, private value?: T) {} static Some(value: T): Option { return new Option(OptionType.Some, value) } static None(): Option { return new Option(OptionType.None) } isSome() { return this.type === OptionType.Some } isNone() { return this.type === OptionType.None } map(mapper: (val: T) => U): Option { if (this.isSome()) { return Option.Some(mapper(this.value!)) } else { return Option.None() } } filter(predicate: (val: T) => boolean): Option { if (this.isSome()) { if (predicate(this.value!)) { return Option.Some(this.value as U) } else { return Option.None() } } else { return Option.None() } } mapOr(defaultValue: U, mapper: (val: T) => U): U { if (this.isSome()) { return mapper(this.value!) } else { return defaultValue } } mapOrElse(createDefaultValue: () => U, mapper: (val: T) => U): U { if (this.isSome()) { return mapper(this.value!) } else { return createDefaultValue() } } /** * @throws {Error} */ unwrap(): T { if (this.isSome()) { return this.value! } else { throw new Error('unwrap called on a None') } } unwrapOr(defaultValue: U): T | U { if (this.isSome()) { return this.value! } else { return defaultValue } } unwrapOrElse(createDefaultValue: () => U): T | U { if (this.isSome()) { return this.value! } else { return createDefaultValue() } } /** * @throws {Error} */ expect(message: string): T { if (this.isSome()) { return this.value! } else { throw new Error(message) } } okOr(err: E): Result { if (this.isSome()) { return Result.Ok(this.value!) } else { return Result.Err(err) } } okOrElse(createErr: () => E): Result { if (this.isSome()) { return Result.Ok(this.value!) } else { return Result.Err(createErr()) } } }