@ts-rust/std
Version:
Rust-inspired utilities for TypeScript: Option, Result, and error handling for safer, more predictable code.
1,241 lines • 45.3 kB
TypeScript
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 `true` if the option is {@link Some} and the contained value
* equals `value` using the `===` operator.
*
* @example
* ```ts
* const x = some(2);
* const y = none<number>();
*
* expect(x.contains(2)).toBe(true);
* expect(x.contains(3)).toBe(false);
* expect(y.contains(2)).toBe(false);
* ```
*/
contains(value: T): boolean;
/**
* 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 `undefined` if {@link None}.
*
* @example
* ```ts
* const x = some(2);
* const y = none<number>();
*
* expect(x.unwrapOrDefault()).toBe(2);
* expect(y.unwrapOrDefault()).toBeUndefined();
* ```
*/
unwrapOrDefault(): T | undefined;
/**
* 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