UNPKG

@ts-rust/std

Version:

Rust-inspired utilities for TypeScript: Option, Result, and error handling for safer, more predictable code.

1,213 lines 44.5 kB
import type { Cloneable, Recoverable } from "../types"; import type { Result, PendingResult } from "../result"; import type { SomeAwaitedValues, SomeValues } from "./types"; /** * Represents an {@link Option} containing a value of type `T`. */ export type Some<T> = Optional<T> & { [phantom]: "some"; readonly value: T; }; /** * Represents an empty {@link Option} with no value. * * Unlike {@link Some}, it does not provide a `value` property. */ export type None<T> = Optional<T> & { [phantom]: "none"; }; /** * A type that represents either a value ({@link Some | Some\<T>}) or * no value ({@link None | None\<T>}). * * Inspired by Rust's {@link https://doc.rust-lang.org/std/option/enum.Option.html | Option}, * it is used to handle values that may or may not be present, avoiding null or undefined * checks. This is a union of {@link Some} and {@link None} variants. */ export type Option<T> = Some<T> | None<T>; /** * A synchronous {@link Option} where the contained value `T` is guaranteed to be * non-`PromiseLike`, ensuring immediate availability without awaiting. * * This restricted {@link Option} variant enforces synchronous values for methods * like {@link Optional.insert | insert}, {@link Optional.getOrInsert | getOrInsert}, * and {@link Optional.getOrInsertWith | getOrInsertWith}, which mutate the option. * Use it when you need a type-safe, synchronous option. */ export type SettledOption<T> = Option<Awaited<T>>; /** * Interface defining the core functionality of an {@link Option}, inspired by Rust's * {@link https://doc.rust-lang.org/std/option/enum.Option.html | Option} type, with * additional methods tailored for TypeScript. * * Represents a value that may or may not be present, offering a robust alternative to * `null` or `undefined`. It includes most Rust `Option` methods (e.g., `map`, `andThen`, * `unwrap`) for safe value handling, plus TypeScript-specific extensions like * {@link toPending} and async variants of {@link and} with `Promise` support. * * For methods accepting predicates (e.g., {@link orElse}, {@link filter}, {@link map}, * {@link andThen}), exceptions in the provided function result in {@link None}, ensuring * predictable, type-safe behavior. If error handling is a concern, use {@link okOr} or * {@link okOrElse} to convert to a {@link Result}. * * Implementations like {@link Some} and {@link None} enable pattern matching, * transformations, and error handling in a type-safe way. */ export interface Optional<T> { /** * Returns {@link None} if this option is {@link None}, otherwise returns `x`. * * @example * ```ts * const x = some(2); * const y = none<number>(); * * expect(x.and(some(3))).toStrictEqual(some(3)); * expect(x.and(none())).toStrictEqual(none()); * expect(y.and(some(3))).toStrictEqual(none()); * expect(y.and(none())).toStrictEqual(none()); * ``` */ and<U>(x: Option<U>): Option<U>; /** * Applies `f` to the value if {@link Some}, returning its result; otherwise, * returns {@link None}. Also known as `flatMap`. * * @notes * - *Default*: If `f` throws, returns {@link None}. * * @example * ```ts * const x = some(2); * const y = none<number>(); * * expect(x.andThen(n => some(n * 2))).toStrictEqual(some(4)); * expect(x.andThen(_ => { throw new Error() })).toStrictEqual(none()); * expect(x.andThen(_ => none())).toStrictEqual(none()); * expect(y.andThen(n => some(n * 2))).toStrictEqual(none()); * ``` */ andThen<U>(f: (x: T) => Option<U>): Option<U>; /** * Returns a clone of the {@link Option}. * * Only available on {@link Option}s with {@link Cloneable} values. * * @example * ```ts * const x = some(1); * const y = some({ a: 1, clone: () => ({ a: 1 }) }); * * expect(x.clone()).toStrictEqual(some(1)); * expect(x.clone()).not.toBe(x); // Different reference * expect(x.clone().unwrap()).toBe(1); * expect(y.clone()).toStrictEqual(some({ a: 1 })); * ``` */ clone<U>(this: Option<Cloneable<U>>): Option<U>; /** * Combines this {@link Option} with other `Option` instances into a single * `Option` containing a tuple of values. * * The `combine` method takes an arbitrary number of `Option` instances, * all sharing the same error-free structure. If all `Option` instances * (including this one) are `Some`, it returns an `Option` with a tuple of * their values in the order provided. If any `Option` is `None`, it returns * `None`. The resulting tuple includes the value of this `Option` as the first * element, followed by the values from the provided `Option` instances. * * @example * ```ts * const a = some(Promise.resolve(1)); * const b = some("hi"); * const c = none<Date>(); * const d = a.combine(b, c); // Option<[Promise<number>, string, Date]> * ``` */ combine<U extends Option<unknown>[]>(...opts: U): Option<[T, ...SomeValues<U>]>; /** * Returns a **shallow** copy of the {@link Option}. * * @example * ```ts * const value = { a: 1 }; * const x = some(value); * const y = none<{ a: number }>(); * * expect(x.copy()).toStrictEqual(some({ a: 1 })); * expect(x.copy()).not.toBe(x); // Different option reference * expect(x.copy().unwrap()).toBe(value); // Same value reference * expect(y.copy()).toStrictEqual(none()); * ``` */ copy(): Option<T>; /** * Returns the value if {@link Some}, or throws an {@link OptionError} with `msg` * (or a default message) if {@link None}. * * @throws * - {@link OptionError} if this is {@link None} * * @example * ```ts * const x = some(42); * const y = none<number>(); * * expect(x.expect("Missing value")).toBe(42); * expect(() => y.expect("Missing value")).toThrow("Missing value"); * expect(() => y.expect()).toThrow("`expect`: called on `None`"); * ``` */ expect(this: SettledOption<T>, msg?: string): T; /** * Returns the option if {@link Some} and `f` returns `true`, otherwise * returns {@link None}. * * @notes * - *Default*: If `f` throws, {@link None} is returned. * * @example * ```ts * const x = some(2); * const y = none<number>(); * * expect(x.filter(n => n > 0)).toStrictEqual(some(2)); * expect(x.filter(n => n < 0)).toStrictEqual(none()); * expect(x.filter(_ => { throw new Error() })).toStrictEqual(none()); * expect(y.filter(n => n > 0)).toStrictEqual(none()); * ``` */ filter(f: (x: T) => boolean): Option<T>; /** * Flattens an {@link Option} of an {@link Option} into a single {@link Option}. * * @example * ```ts * const x: Option<Option<Option<number>>> = some(some(some(6))); * const y: Option<Option<number>> = x.flatten(); * const z = none<Option<Option<number>>>(); * * expect(x.flatten()).toStrictEqual(some(some(6))); * expect(y.flatten()).toStrictEqual(some(6)); * expect(z.flatten()).toStrictEqual(none()); * ``` */ flatten<U>(this: Option<Option<U>>): Option<U>; /** * Returns the contained value if {@link Some}, or inserts and returns `x` * if {@link None}. * * See also {@link insert} method, which updates the value even if the option * already contains {@link Some}. * * @notes * - *Mutation*: This method mutates the {@link Option}. * * @example * ```ts * const x = some(2); * const y = none<number>(); * * expect(x.getOrInsert(5)).toBe(2); * expect(y.getOrInsert(5)).toBe(5); * expect(y).toStrictEqual(some(5)); // y is mutated * ``` */ getOrInsert(this: SettledOption<T>, x: T): T; /** * Returns the value if {@link Some}, or inserts and returns the result of `f` * if {@link None}. * * @throws * - {@link OptionError} if `f` throws, with the original error as * {@link OptionError.reason} * * @notes * - *Mutation*: Mutates this option to {@link Some} with `f`’s result if {@link None}. * If `f` throws, the option remains unchanged. * * @example * ```ts * const x = some(2); * const y = none<number>(); * const z = none<number>(); * * expect(x.getOrInsertWith(() => 5)).toBe(2); * expect(y.getOrInsertWith(() => 5)).toBe(5); * expect(y).toStrictEqual(some(5)); // Mutated * expect(() => z.getOrInsertWith(() => { throw new Error() })).toThrow(OptionError); * expect(z).toStrictEqual(none()); // Unchanged * ``` */ getOrInsertWith(this: SettledOption<T>, f: () => T): T; /** * Inserts `x` into the option and returns it, overwriting any existing value. * * See also {@link getOrInsert} method, which doesn’t update the value if the * option already contains {@link Some}. * * @notes * - *Mutation*: This method mutates the {@link Option}. * * @example * ```ts * const x = some(2); * const y = none<number>(); * * expect(x.insert(5)).toBe(5); * expect(x).toStrictEqual(some(5)); * expect(y.insert(5)).toBe(5); * expect(y).toStrictEqual(some(5)); * ``` */ insert(this: SettledOption<T>, x: T): T; /** * Calls `f` with the value if {@link Some}, then returns a copy of this option. * * If `f` throws or returns a `Promise` that rejects, the error is ignored. * * @notes * - Returns a new {@link Option} instance, not the original reference. * * @example * ```ts * const x = some(2); * const y = none<number>(); * let sideEffect = 0; * * expect(x.inspect(n => (sideEffect = n))).toStrictEqual(some(2)); * expect(x.inspect(_ => { throw new Error() })).toStrictEqual(some(2)); * expect(sideEffect).toBe(2); * expect(y.inspect(n => (sideEffect = n))).toStrictEqual(none()); * expect(sideEffect).toBe(2); // Unchanged * ``` */ inspect(f: (x: T) => unknown): Option<T>; /** * Returns `true` if the option is {@link None}. * * @example * ```ts * const x = some(2); * const y = none<number>(); * * expect(x.isNone()).toBe(false); * expect(y.isNone()).toBe(true); * ``` */ isNone(): this is None<T>; /** * Returns `true` if the option is {@link None} or if `f` returns `true` for the contained value. * * @notes * - *Default*: If `f` throws, `false` is returned. * * @example * ```ts * const x = some(2); * const y = none<number>(); * * expect(x.isNoneOr(n => n > 0)).toBe(true); * expect(x.isNoneOr(_ => { throw new Error() })).toBe(false); * expect(x.isNoneOr(n => n < 0)).toBe(false); * expect(y.isNoneOr(n => n > 0)).toBe(true); * ``` */ isNoneOr(f: (x: T) => boolean): boolean; /** * Returns `true` if the option is {@link Some}. * * @example * ```ts * const x = some(2); * const y = none<number>(); * * expect(x.isSome()).toBe(true); * expect(y.isSome()).toBe(false); * ``` */ isSome(): this is Some<T>; /** * Returns `true` if the option is {@link Some} and `f` returns `true` * for the contained value. * * @notes * - *Default*: If `f` throws, `false` is returned. * * @example * ```ts * const x = some(2); * const y = none<number>(); * * expect(x.isSomeAnd(n => n > 0)).toBe(true); * expect(x.isSomeAnd(_ => { throw new Error() })).toBe(false); * expect(x.isSomeAnd(n => n < 0)).toBe(false); * expect(y.isSomeAnd(n => n > 0)).toBe(false); * ``` */ isSomeAnd(f: (x: T) => boolean): this is Some<T> & boolean; /** * Returns an iterator over this option’s value, yielding it if {@link Some} * or nothing if {@link None}. * * @notes * - Yields exactly one item for {@link Some}, or zero items for {@link None}. * - Compatible with `for...of` loops and spread operators. * * @example * ```ts * const x = some(42); * const y = none<number>(); * * const iterX = x.iter(); * expect(iterX.next()).toEqual({ value: 42, done: false }); * expect(iterX.next()).toEqual({ done: true }); * * const iterY = y.iter(); * expect(iterY.next()).toEqual({ done: true }); * * expect([...x.iter()]).toEqual([42]); * expect([...y.iter()]).toEqual([]); * ``` */ iter(): IterableIterator<T, T, void>; /** * Maps the contained value with `f` if {@link Some}, returning a new * {@link Option}; otherwise, returns {@link None}. * * @notes * - *Default*: If `f` throws, {@link None} is returned. * * @example * ```ts * const x = some(2); * const y = none<number>(); * * expect(x.map(n => n * 2)).toStrictEqual(some(4)); * expect(x.map(_ => { throw new Error() })).toStrictEqual(none()); * expect(y.map(n => n * 2)).toStrictEqual(none()); * ``` */ map<U>(f: (x: T) => Awaited<U>): Option<U>; /** * Maps this option by applying a callback to its full state, executing the * callback for both {@link Some} and {@link None}, returning a new {@link Option}. * * Unlike {@link andThen}, which only invokes the callback for {@link Some}, * this method always calls `f`, passing the entire {@link Option} as its argument. * * @notes * - *Default*: If `f` throws, the error is silently ignored and {@link None} * is returned. * * @example * ```ts * const someOpt = some(42); * const noneOpt = none<number>(); * const undefOpt = some(undefined); * * expect(someOpt.mapAll(opt => some(opt.unwrapOr(0) + 1))).toStrictEqual(some(43)); * expect(noneOpt.mapAll(opt => some(opt.unwrapOr(0) + 1))).toStrictEqual(some(1)); * expect(undefOpt.mapAll(opt => some(opt.isSome() ? "some" : "none"))).toStrictEqual(some("some")); * ``` */ mapAll<U>(f: (x: Option<T>) => Option<U>): Option<U>; /** * Maps this option by applying a callback to its full state, executing the * callback for both {@link Some} and {@link None}, returning a {@link PendingOption}. * * Unlike {@link andThen}, which only invokes the callback for {@link Some}, * this method always calls `f`, passing the entire {@link Option} as its argument. * * @notes * - *Default*: If `f` returns a `Promise` that rejects, the resulting * {@link PendingOption} resolves to {@link None}. * * @example * ```ts * const someOpt = some(42); * const noneOpt = none<number>(); * * const mappedSome = someOpt.mapAll(opt => Promise.resolve(some(opt.unwrapOr(0)))); * expect(isPendingOption(mappedSome)).toBe(true); * expect(await mappedSome).toStrictEqual(some(42)); * * const mappedNone = noneOpt.mapAll(opt => Promise.resolve(some(opt.unwrapOr(0) + 1))); * expect(isPendingOption(mappedNone)).toBe(true); * expect(await mappedNone).toStrictEqual(some(1)); * ``` */ mapAll<U>(f: (x: Option<T>) => Promise<Option<U>>): PendingOption<Awaited<U>>; /** * Returns `f` applied to the value if {@link Some}, otherwise returns `def`. * * @notes * - *Default*: If `f` throws, returns `def`. * * @example * ```ts * const x = some(2); * const y = none<number>(); * * expect(x.mapOr(0, n => n * 2)).toBe(4); * expect(x.mapOr(0, _ => { throw new Error() })).toBe(0); * expect(y.mapOr(0, n => n * 2)).toBe(0); * ``` */ mapOr<U>(this: SettledOption<T>, def: Awaited<U>, f: (x: T) => Awaited<U>): U; /** * Returns `f` applied to the contained value if {@link Some}, otherwise * returns the result of `mkDef`. * * @throws * - {@link OptionError} if `mkDef` is called and throws an exception. Original * error will be set as {@link OptionError.reason}. * * @notes * - *Default*: If `f` throws, the error is silently ignored and result of * `mkDef` is returned. * * @example * ```ts * const x = some(2); * const y = none<number>(); * * expect(x.mapOrElse(() => 0, n => n * 2)).toBe(4); * expect(x.mapOrElse(() => 1, _ => { throw new Error() })).toBe(1); * expect(() => x.mapOrElse(() => { throw new Error() }, _ => { throw new Error() })).toThrow(OptionError); * expect(y.mapOrElse(() => 0, n => n * 2)).toBe(0); * ``` */ mapOrElse<U>(this: SettledOption<T>, mkDef: () => Awaited<U>, f: (x: T) => Awaited<U>): U; /** * Matches the option, returning `f` applied to the value if {@link Some}, * or `g` if {@link None}. * * @throws * - {@link OptionError} if `f` or `g` throws an exception, original error will be * set as {@link OptionError.reason}. * * @notes * - If `f` or `g` returns a `Promise` that rejects, the caller is responsible * for handling the rejection. * * @example * ```ts * const x = some(2); * const y = none<number>(); * * expect(x.match(n => n * 2, () => 0)).toBe(4); * expect(() => x.match(_ => { throw new Error() }, () => 0)).toThrow(OptionError); * expect(y.match(n => n * 2, () => 0)).toBe(0); * expect(() => y.match(n => n * 2, () => { throw new Error() })).toThrow(OptionError); * ``` */ match<U, F = U>(this: SettledOption<T>, f: (x: T) => Awaited<U>, g: () => Awaited<F>): U | F; /** * Converts to a {@link Result}, using `y` as the error value if {@link None}. * * {@link Some | Some(v)} is mapped to {@link Ok | Ok(v)} and {@link None} to * {@link Err | Err(y)}. * * @example * ```ts * const x = some(2); * const y = none<number>(); * * expect(x.okOr("error")).toStrictEqual(ok(2)); * expect(y.okOr("error")).toStrictEqual(err("error")); * ``` */ okOr<E>(y: Awaited<E>): Result<T, E>; /** * Converts to a {@link Result}, using the result of `mkErr` as the error * value if {@link None}. * * {@link Some | Some(v)} is mapped to {@link Ok | Ok(v)} and {@link None} * to {@link Err | Err(mkErr())}. * * @example * ```ts * const x = some(2); * const y = none<number>(); * * expect(x.okOrElse(() => "error")).toStrictEqual(ok(2)); * expect(y.okOrElse(() => "error")).toStrictEqual(err("error")); * ``` */ okOrElse<E>(mkErr: () => Awaited<E>): Result<T, E>; /** * Returns the current option if it is {@link Some}, otherwise returns `x`. * * @example * ```ts * const x = some(2); * const y = none<number>(); * * expect(x.or(some(3))).toStrictEqual(some(2)); * expect(x.or(none())).toStrictEqual(some(2)); * expect(y.or(some(3))).toStrictEqual(some(3)); * expect(y.or(none())).toStrictEqual(none()); * ``` */ or(x: Option<T>): Option<T>; /** * Returns the current option if {@link Some}, otherwise returns the result of `f`. * * @notes * - *Default*: If `f` throws, {@link None} is returned. * * @example * ```ts * const x = some(2); * const y = none<number>(); * * expect(x.orElse(() => some(3))).toStrictEqual(some(2)); * expect(y.orElse(() => some(3))).toStrictEqual(some(3)); * expect(y.orElse(() => { throw new Error() })).toStrictEqual(none()); * expect(y.orElse(() => none())).toStrictEqual(none()); * ``` */ orElse(f: () => Option<T>): Option<T>; /** * Replaces the current value with `x` and returns the old {@link Option}. * * @notes * - *Mutation*: This method mutates the {@link Option}. * * @example * ```ts * const x = some(2); * const y = none<number>(); * * expect(x.replace(5)).toStrictEqual(some(2)); * expect(x).toStrictEqual(some(5)); * expect(y.replace(5)).toStrictEqual(none()); * expect(y).toStrictEqual(some(5)); // y is mutated * ``` */ replace(x: T): Option<T>; /** * Takes the value out of the {@link Option}, leaving {@link None} in its place. * * @notes * - *Mutation*: This method mutates the {@link Option}. * * @example * ```ts * const x = some(2); * const y = none<number>(); * * expect(x.take()).toStrictEqual(some(2)); * expect(x).toStrictEqual(none()); * expect(y.take()).toStrictEqual(none()); * expect(y).toStrictEqual(none()); * ``` */ take(): Option<T>; /** * Takes the value out of the {@link Option}, but only if `f` returns `true`. * Similar to {@link take}, but conditional. * * @notes * - *Mutation*: This method mutates the {@link Option}. * - *Default*: If `f` throws, {@link None} is returned and the original * value **remains unchanged**. * * @example * ```ts * const x = some(2); * const y = none<number>(); * const z = some(1); * * expect(x.takeIf(n => n > 0)).toStrictEqual(some(2)); * expect(x).toStrictEqual(none()); * expect(x.takeIf(n => n < 0)).toStrictEqual(none()); * expect(y.takeIf(n => n > 0)).toStrictEqual(none()); * expect(z.takeIf(_ => { throw new Error() })).toStrictEqual(none()) * expect(z).toStrictEqual(some(1)); * ``` */ takeIf(f: (x: T) => boolean): Option<T>; /** * Executes `f` with a copy of this option, then returns a new copy unchanged. * * Useful for side-effects like logging, works with both {@link Some} and {@link None}. * * @notes * - If `f` throws or rejects, the error is ignored. * - If `f` returns a promise, the promise is not awaited before returning. * * @example * ```ts * const x = some(42); * const y = none<number>(); * let log = ""; * * expect(x.tap(opt => (log = opt.toString()))).toStrictEqual(some(42)); * expect(log).toBe("Some { 42 }"); * expect(y.tap(opt => (log = opt.toString()))).toStrictEqual(none()); * expect(log).toBe("None"); * ``` */ tap(f: (x: Option<T>) => unknown): Option<T>; /** * Maps this option to a {@link PendingOption} by supplying a shallow * {@link Optional.copy | copy} of this option to {@link PendingOption} factory. * * Useful for transposing an option with `PromiseLike` value to a * {@link PendingOption} with `Awaited` value. * * @notes * - *Default*: If inner `T` is a promise-like that rejects, maps to a * {@link PendingOption} with {@link None}. * * @example * ```ts * const value = { a: 1 }; * const x = some(value); * const y = none<number>(); * const pendingX = x.toPending(); * * expect(isPendingOption(pendingX)).toBe(true); * expect(await pendingX).toStrictEqual(some({ a: 1 })); * value.a = 2; * expect(await pendingX).toStrictEqual(some({ a: 2 })); * expect(await y.toPending()).toStrictEqual(none()); * ``` */ toPending(): PendingOption<Awaited<T>>; /** * Maps this option to a {@link PendingOption} by supplying a * {@link Optional.clone | clone} of this option to {@link PendingOption} factory. * * Useful for transposing an option with `PromiseLike` value to a * {@link PendingOption} with `Awaited` value. * * @notes * - *Default*: If inner `T` is a promise-like that rejects, maps to a * {@link PendingOption} with {@link None}. * * @example * ```ts * const value = { a: 0, clone: () => ({ a: 0 })}; * const x = some(value); * const y = none<number>(); * const pendingX = x.toPendingCloned(); * * expect(isPendingOption(pendingX)).toBe(true); * expect((await pendingX).unwrap().a).toBe(0); * value.a = 42; * expect((await pendingX).unwrap().a).toBe(0); * expect(await y.toPendingCloned()).toStrictEqual(none()); * ``` */ toPendingCloned(this: Option<Cloneable<T>>): PendingOption<Awaited<T>>; /** * Returns a string representation of the {@link Option}. * * @example * ```ts * const x = some(2); * const y = none<number>(); * * expect(x.toString()).toBe("Some { 2 }"); * expect(y.toString()).toBe("None"); * ``` */ toString(): string; /** * Transposes an {@link Option} of a {@link Result} into a {@link Result} * of an {@link Option}. * * Maps `None` to `Ok(None)`, `Some(Ok(_))` to `Ok(Some(_))`, * and `Some(Err(_))` to `Err(_)`. * * @example * ```ts * const x = none<Result<number, string>>(); * const y = some<Result<number, string>>(ok(2)); * const z = some<Result<number, string>>(err("error")); * * expect(x.transpose()).toStrictEqual(ok(none())); * expect(y.transpose()).toStrictEqual(ok(some(2))); * expect(z.transpose()).toStrictEqual(err("error")); * ``` */ transpose<U, E>(this: Option<Result<U, E>>): Result<Option<U>, E>; /** * Returns the value if {@link Some}, or throws an {@link OptionError} if {@link None}. * * @throws * - {@link OptionError} if this is {@link None} * * @example * ```ts * const x = some(2); * const y = none<number>(); * * expect(x.unwrap()).toBe(2); * expect(() => y.unwrap()).toThrow("`unwrap`: called on `None`"); * ``` */ unwrap(this: SettledOption<T>): T; /** * Returns the contained value if {@link Some}, or `def` if {@link None}. * * @example * ```ts * const x = some(2); * const y = none<number>(); * * expect(x.unwrapOr(0)).toBe(2); * expect(y.unwrapOr(0)).toBe(0); * ``` */ unwrapOr(this: SettledOption<T>, def: Awaited<T>): T; /** * Returns the contained value if {@link Some}, or the result of `mkDef` if {@link None}. * * @throws * - {@link OptionError} if `mkDef` throws, original error will be set as * {@link OptionError.reason}. * * @example * ```ts * const x = some(2); * const y = none<number>(); * * expect(x.unwrapOrElse(() => 0)).toBe(2); * expect(y.unwrapOrElse(() => 0)).toBe(0); * expect(() => y.unwrapOrElse(() => { throw new Error() })).toThrow(OptionError); * ``` */ unwrapOrElse(this: SettledOption<T>, mkDef: () => Awaited<T>): T; /** * Returns {@link Some} if exactly one of `this` or `y` is {@link Some}, otherwise returns {@link None}. * * @example * ```ts * const x = some(2); * const y = none<number>(); * * expect(x.xor(some(3))).toStrictEqual(none()); * expect(x.xor(none())).toStrictEqual(some(2)); * expect(y.xor(some(3))).toStrictEqual(some(3)); * expect(y.xor(none())).toStrictEqual(none()); * ``` */ xor(y: Option<T>): Option<T>; /** * Returns a {@link PendingOption} with {@link Some} if exactly one of `this` or `y` is * {@link Some}, otherwise with {@link None}. * * @example * ```ts * const x = some(2); * const y = none<number>(); * * expect(isPendingOption(x.xor(Promise.resolve(some(3))))).toBe(true); * expect(await x.xor(Promise.resolve(some(3)))).toStrictEqual(none()); * expect(await x.xor(Promise.resolve(none()))).toStrictEqual(some(2)); * expect(await y.xor(Promise.resolve(some(3)))).toStrictEqual(some(3)); * ``` */ xor(y: Promise<Option<T>>): PendingOption<Awaited<T>>; } /** * Interface defining an asynchronous {@link Option} that wraps a `Promise` * resolving to an {@link Option}. * * Extends {@link Option} functionality for pending states, with methods mirroring * their synchronous counterparts but returning {@link PendingOption} or `Promise` * for async operations. Rejections typically resolve to {@link None} unless otherwise * specified. */ export interface PendingOption<T> extends PromiseLike<Option<T>>, Recoverable<Option<T>> { /** * Returns a {@link PendingOption} with {@link None} if this option resolves to * {@link None}, otherwise returns a {@link PendingOption} with `x`. * * This is the asynchronous version of {@link Optional.and | and}. * * @notes * - *Default*: If `x` is a `Promise` and rejects, {@link None} is returned. * * @example * ```ts * const x = pendingOption(some(2)); * const y = pendingOption(none<number>()); * * expect(await x.and(some(3))).toStrictEqual(some(3)); * expect(await x.and(Promise.resolve(some(3)))).toStrictEqual(some(3)); * expect(await x.and(none())).toStrictEqual(none()); * expect(await x.and(Promise.resolve(none()))).toStrictEqual(none()); * expect(await y.and(some(3))).toStrictEqual(none()); * expect(await y.and(Promise.resolve(none()))).toStrictEqual(none()); * ``` */ and<U>(x: Option<U> | PendingOption<U> | Promise<Option<U>>): PendingOption<Awaited<U>>; /** * Returns a {@link PendingOption} with {@link None} if this {@link Option} resolves * to {@link None}, otherwise applies `f` to the resolved value and returns the result. * * This is the asynchronous version of {@link Optional.andThen | andThen}. * * @notes * - *Default*: If `f` rejects or throws, {@link None} is returned. * * @example * ```ts * const x = pendingOption(some(2)); * const y = pendingOption(none<number>()); * * expect(await x.andThen(n => some(n * 2))).toStrictEqual(some(4)); * expect(await x.andThen(n => Promise.resolve(some(n * 2)))).toStrictEqual(some(4)); * expect(await x.andThen(_ => none())).toStrictEqual(none()); * expect(await y.andThen(n => some(n * 2))).toStrictEqual(none()); * ``` */ andThen<U>(f: (x: T) => Option<U> | PendingOption<U> | Promise<Option<U>>): PendingOption<Awaited<U>>; /** * Combines this {@link PendingOption} with other {@link Option} or `PendingOption` * instances into a single `PendingOption` containing a tuple of resolved values. * * The `combine` method takes an arbitrary number of `Option` or `PendingOption` * instances. It resolves all inputs and returns a `PendingOption` that, when * resolved, contains an `Option` with a tuple of their values if all resolve * to `Some`. If any input resolves to `None`, the result resolves to `None`. * The resulting tuple includes the resolved value of this `PendingOption` as * the first element, followed by the resolved values from the provided instances. * * @example * ```ts * const a = pendingSome(1); * const b = some(Promise.resolve("hi")); * const c = none<Error>(); * const d = pendingNone<Promise<Date>>(); * const e = a.combine(b, c, d); // PendingOption<[number, string, Error, Date]> * ``` */ combine<U extends (Option<unknown> | PendingOption<unknown>)[]>(...opts: U): PendingOption<[Awaited<T>, ...SomeAwaitedValues<U>]>; /** * Returns a {@link PendingOption} with {@link None} if this option resolves to * {@link None}, otherwise calls `f` with the resolved value and returns * a {@link PendingOption} with the original value if `f` resolves to `true`, * or {@link None} otherwise. * * This is the asynchronous version of {@link Optional.filter | filter}. * * @notes * - *Default*: If `f` rejects or throws, {@link None} is returned. * * @example * ```ts * const x = pendingOption(some(2)); * const y = pendingOption(none<number>()); * * expect(await x.filter(n => n > 0)).toStrictEqual(some(2)); * expect(await x.filter(n => Promise.resolve(n < 0))).toStrictEqual(none()); * expect(await y.filter(_ => true)).toStrictEqual(none()); * ``` */ filter(f: (x: T) => boolean | Promise<boolean>): PendingOption<T>; /** * Flattens a {@link PendingOption} of a {@link PendingOption} or {@link Option}, * resolving nested pending states. * * This is the asynchronous version of {@link Optional.flatten | flatten}. * * @notes * - *Default*: If inner {@link Option} is wrapped in a `Promise` and rejects, * flattened {@link PendingOption} with {@link None} is returned. * * @example * ```ts * const option1: PendingOption<Option<number>> = getPendingOption(); * option1.flatten(); // PendingOption<number> * * const option2: PendingOption<PendingOption<number>> = getPendingOption(); * option2.flatten(); // PendingOption<number> * * const option3: PendingOption<PendingOption<PendingOption<number>>> = getPendingOption(); * option3.flatten(); // PendingOption<Option<number>> * ``` */ flatten<U>(this: PendingOption<Option<U>> | PendingOption<PendingOption<U>> | PendingOption<PromiseLike<Option<U>>>): PendingOption<Awaited<U>>; /** * Calls `f` with the resolved value if this option is {@link Some}, then returns this * {@link PendingOption} unchanged. Useful for side effects. * * This is the asynchronous version of {@link Optional.inspect | inspect}. * * @notes * - Returns a new {@link PendingOption} instance with the same value as the original, * rather than the exact same reference. The returned option is a distinct object, * preserving the original value. * * @example * ```ts * const x = pendingOption(some(2)); * const y = pendingOption(none<number>()); * let sideEffect = 0; * * expect(await x.inspect(n => (sideEffect = n))).toStrictEqual(some(2)); * expect(sideEffect).toBe(2); * expect(await y.inspect(n => (sideEffect = n))).toStrictEqual(none()); * expect(sideEffect).toBe(2); // Unchanged * ``` */ inspect(f: (x: T) => unknown): PendingOption<T>; /** * Returns an async iterator over this pending option’s value, yielding it if * it resolves to {@link Some} or nothing if it resolves to {@link None}. * * @notes * - Yields exactly one item for a resolved {@link Some}, or zero items for * a resolved {@link None}. * - Compatible with `for await...of` loops and async spread operators (with caution). * * @example * ```ts * const x = some(42).toPending(); * const y = none<number>().toPending(); * * const iterX = x.iter(); * expect(await iterX.next()).toEqual({ value: 42, done: false }); * expect(await iterX.next()).toEqual({ done: true }); * * const iterY = y.iter(); * expect(await iterY.next()).toEqual({ done: true }); * * async function collect(iter) { * const result = []; * for await (const val of iter) result.push(val); * return result; * } * expect(await collect(x.iter())).toEqual([42]); * expect(await collect(y.iter())).toEqual([]); * ``` */ iter(): AsyncIterableIterator<Awaited<T>, Awaited<T>, void>; /** * Maps the resolved value with `f`, returning a {@link PendingOption} with the * result if {@link Some}, or {@link None} if {@link None}. * * This is the async version of {@link Optional.map | map}. * * @notes * - If `f` throws or rejects, returns {@link None}. * * @example * ```ts * const x = pendingOption(some(2)); * const y = pendingOption(none<number>()); * * expect(await x.map(n => n * 2)).toStrictEqual(some(4)); * expect(await x.map(n => Promise.resolve(n * 2))).toStrictEqual(some(4)); * expect(await y.map(n => n * 2)).toStrictEqual(none()); * ``` */ map<U>(f: (x: T) => U): PendingOption<Awaited<U>>; /** * Maps this option by applying a callback to its full state, executing the * callback for both {@link Some} and {@link None}, returning a new {@link PendingOption}. * * Unlike {@link andThen}, which only invokes the callback for {@link Some}, * this method always calls `f`, passing the entire {@link Option} as its argument. * * This is the asynchronous version of {@link Optional.mapAll | mapAll}. * * @notes * - *Default*: If `f` throws or returns a `Promise` that rejects, the newly * created {@link PendingOption} will resolve to a {@link None}. * * @example * ```ts * const someOpt = pendingOption(some(42)); * const noneOpt = pendingOption(none<number>()); * * const someMapped = someOpt.mapAll(opt => Promise.resolve(some(opt.unwrapOr(0)))); * expect(await someMapped).toStrictEqual(some(42)); * * const noneMapped = noneOpt.mapAll(opt => Promise.resolve(some(opt.unwrapOr(0) + 1))); * expect(await noneMapped).toStrictEqual(some(1)); * ``` */ mapAll<U>(f: (x: Option<T>) => Option<U> | PendingOption<U> | Promise<Option<U>>): PendingOption<Awaited<U>>; /** * Matches the resolved option, returning `f` applied to the value if {@link Some}, * or `g` if {@link None}. Returns a `Promise` with the result. * * This is the asynchronous version of {@link Optional.match | match}. * * @throws * - Rejects with {@link OptionError} if `f` or `g` throws an exception or rejects, * original error will be set as {@link OptionError.reason}. * * @notes * - If `f` or `g` throws or returns a rejected `Promise`, the returned promise * rejects with the original error. In this case the caller is responsible * for handling the rejection. * * @example * ```ts * const x = pendingOption(some(2)); * const y = pendingOption(none<number>()); * * expect(await x.match(n => n * 2, () => 0)).toBe(4); * expect(await y.match(n => n * 2, () => 0)).toBe(0); * await expect(y.match(n => n * 2, () => { throw new Error() })).rejects.toThrow(OptionError); * ``` */ match<U, F = U>(f: (x: T) => U, g: () => F): Promise<Awaited<U | F>>; /** * Converts to a {@link PendingResult}, using `y` as the error value if this * {@link PendingOption} resolves to {@link None}. * * This is the asynchronous version of {@link Optional.okOr | okOr}, * check it for more details. * * @example * ```ts * const x = pendingOption(some(2)); * const y = pendingOption(none<number>()); * * expect(await x.okOr("error")).toStrictEqual(ok(2)); * expect(await y.okOr("error")).toStrictEqual(err("error")); * ``` */ okOr<E>(y: Awaited<E>): PendingResult<T, E>; /** * Converts to a {@link PendingResult}, using the result of `mkErr` * as the error value if this resolves to {@link None}. * * This is the asynchronous version of {@link Optional.okOrElse | okOrElse}. * * @example * ```ts * const x = pendingOption(some(2)); * const y = pendingOption(none<number>()); * * expect(await x.okOrElse(() => "error")).toStrictEqual(ok(2)); * expect(await y.okOrElse(() => Promise.resolve("error"))).toStrictEqual(err("error")); * ``` */ okOrElse<E>(mkErr: () => E | Promise<E>): PendingResult<T, E>; /** * Returns this {@link PendingOption} if it resolves to {@link Some}, otherwise * returns a {@link PendingOption} with `x`. * * This is the asynchronous version of {@link Optional.or | or}. * * @notes * - *Default*: If `x` is a `Promise` that rejects, {@link None} is returned. * * @example * ```ts * const x = pendingOption(some(2)); * const y = pendingOption(none<number>()); * * expect(await x.or(some(3))).toStrictEqual(some(2)); * expect(await x.or(Promise.resolve(none()))).toStrictEqual(some(2)); * expect(await y.or(some(3))).toStrictEqual(some(3)); * expect(await y.or(Promise.resolve(none()))).toStrictEqual(none()); * ``` */ or(x: Option<T> | PendingOption<T> | Promise<Option<T>>): PendingOption<Awaited<T>>; /** * Returns this {@link PendingOption} if it resolves to {@link Some}, otherwise * returns a {@link PendingOption} with the result of `f`. * * This is the asynchronous version of {@link Optional.orElse | orElse}. * * @notes * - *Default*: If `f` throws or rejects, {@link None} is returned. * * @example * ```ts * const x = pendingOption(some(2)); * const y = pendingOption(none<number>()); * * expect(await x.orElse(() => some(3))).toStrictEqual(some(2)); * expect(await y.orElse(() => Promise.resolve(some(3)))).toStrictEqual(some(3)); * expect(await y.orElse(() => some(1))).toStrictEqual(some(1)); * ``` */ orElse(f: () => Option<T> | PendingOption<T> | Promise<Option<T>>): PendingOption<Awaited<T>>; /** * Executes `f` with the resolved option, then returns a new {@link PendingOption} * unchanged. * * This is the asynchronous version of {@link Optional.tap | tap}. * * @notes * - If `f` throws or rejects, the error is ignored. * - If `f` returns a promise, the promise is not awaited before returning. * * @example * ```ts * const x = pendingOption(some(42)); * const y = pendingOption(none<number>()); * let log = ""; * * expect(await x.tap(opt => (log = opt.toString()))).toStrictEqual(some(42)); * expect(log).toBe("Some { 42 }"); * expect(await y.tap(opt => (log = opt.toString()))).toStrictEqual(none()); * expect(log).toBe("None"); * ``` */ tap(f: (x: Option<T>) => unknown): PendingOption<T>; /** * Transposes a {@link PendingOption} of a {@link Result} into a {@link PendingResult} * containing an {@link Option}. * * This is the asynchronous version of {@link Optional.transpose | transpose}. * * @example * ```ts * const x = pendingOption(none<Result<number, string>>()); * const y = pendingOption(some<Result<number, string>>(ok(2))); * const z = pendingOption(some<Result<number, string>>(err("error"))); * * expect(await x.transpose()).toStrictEqual(ok(none())); * expect(await y.transpose()).toStrictEqual(ok(some(2))); * expect(await z.transpose()).toStrictEqual(err("error")); * ``` */ transpose<U, E>(this: PendingOption<Result<U, E>>): PendingResult<Option<U>, E>; /** * Returns a {@link PendingOption} with {@link Some} if exactly one of this option or * `y` resolves to {@link Some}, otherwise returns a {@link PendingOption} with * {@link None}. * * This is the asynchronous version of {@link Optional.xor | xor}. * * @notes * - *Default*: If `y` is a `Promise` that rejects, {@link None} is returned. * * @example * ```ts * const x = pendingOption(some(2)); * const y = pendingOption(none<number>()); * * expect(await x.xor(some(3))).toStrictEqual(none()); * expect(await x.xor(Promise.resolve(none()))).toStrictEqual(some(2)); * expect(await y.xor(some(3))).toStrictEqual(some(3)); * expect(await y.xor(Promise.resolve(none()))).toStrictEqual(none()); * ``` */ xor(y: Option<T> | PendingOption<T> | Promise<Option<T>>): PendingOption<Awaited<T>>; } /** * Internal symbol-keyed property used as a type discriminant, holding `"some"` * or `"none"` to indicate whether the {@link Option} is a {@link Some} or * {@link None} variant. * * Not intended for direct user access or modification, this enables TypeScript's * type narrowing for methods like {@link isSome} and {@link isNone}. The `phantom` * symbol ensures module-level privacy, allowing internal state mutation (e.g., * from `None` to `Some`) without external interference. */ export declare const phantom: unique symbol; //# sourceMappingURL=interface.d.ts.map