@ts-rust/std
Version:
Rust-inspired utilities for TypeScript: Option, Result, and error handling for safer, more predictable code.
1,255 lines • 48.9 kB
TypeScript
import type { Option, PendingOption } from "../option";
import type { Cloneable, Recoverable } from "../types";
import type { ResultError } from "./error";
import type { OkAwaitedValues, OkValues } from "./types";
/**
* Represents a successful outcome of a {@link Result}, holding a value
* of type `T`.
*/
export type Ok<T, E> = Resultant<T, E> & {
readonly value: T;
};
/**
* Represents a failed outcome of a {@link Result}, holding a {@link CheckedError}
* of type `E`.
*
* This type ensures errors are checked, distinguishing between expected errors
* of type `E` and unexpected runtime failures wrapped in {@link ResultError}.
*/
export type Err<T, E> = Resultant<T, E> & {
readonly error: CheckedError<E>;
};
/**
* A type representing the outcome of an operation, either a success
* ({@link Ok}) or a checked failure ({@link Err}).
*
* Inspired by Rust’s
* {@link https://doc.rust-lang.org/std/result/enum.Result.html | Result}, this
* type provides a type-safe way to handle computations that may succeed with
* a value of type `T` or fail with a checked error of type `E`, distinguishing
* expected and unexpected failures via {@link CheckedError}.
*/
export type Result<T, E> = Ok<T, E> | Err<T, E>;
/**
* A {@link Result} type where both the value (`T`) and error (`E`) types have
* been resolved from potential `PromiseLike` types to their awaited forms.
*/
export type SettledResult<T, E> = Ok<Awaited<T>, Awaited<E>> | Err<Awaited<T>, Awaited<E>>;
/**
* Represents an expected error of type `E` within a {@link CheckedError}.
*/
export type ExpectedError<E> = EitherError<E> & {
/**
* The expected error value of type `E`.
*/
readonly expected: E;
/**
* Always `undefined`
*/
readonly unexpected: undefined;
/**
* Retrieves the contained error value, either an expected error of type `E` or
* an unexpected {@link ResultError}.
*/
get(): E;
};
/**
* Represents an unexpected error of type {@link ResultError} within a
* {@link CheckedError}.
*/
export type UnexpectedError<E> = EitherError<E> & {
/**
* Always `undefined`.
*/
readonly expected: undefined;
/**
* The unexpected error value of type {@link ResultError}.
*/
readonly unexpected: ResultError;
/**
* Retrieves the contained error value, either an expected error of type `E` or
* an unexpected {@link ResultError}.
*/
get(): ResultError;
};
/**
* A type representing the error state of a {@link Result}, containing either
* an expected error of type `E` or an unexpected {@link ResultError}.
*
* This type ensures exactly one error is present: either an expected error
* (an anticipated failure of type `E`) or an unexpected error (a runtime or
* exceptional failure). Use {@link EitherError.isExpected | isExpected} or
* {@link EitherError.isUnexpected | isUnexpected} to narrow the type if needed.
*/
export type CheckedError<E> = ExpectedError<E> | UnexpectedError<E>;
/**
* Base interface for {@link CheckedError} instances, providing methods to inspect
* and handle the contained error.
*/
export interface EitherError<E> extends Error {
/**
* Applies one of two functions to the contained error based on its type.
*
* Applies the first function in case the inner error is unexpected
* {@link ResultError}, or the second function if the inner error is
* expected `E`.
*/
handle<T>(f: (e: ResultError) => T, g: (e: E) => T): T;
/**
* Checks if this is an expected error, narrowing to {@link ExpectedError}.
*/
isExpected(): this is ExpectedError<E>;
/**
* Checks if this is an unexpected error, narrowing to {@link UnexpectedError}.
*/
isUnexpected(): this is UnexpectedError<E>;
}
/**
* Interface representing the resultant state of an operation, either a success
* ({@link Ok | Ok\<T>}) or an error ({@link Err | Err\<E>}).
*
* Inspired by Rust’s {@link https://doc.rust-lang.org/std/result/enum.Result.html | Result},
* it provides a type-safe alternative to exceptions for handling success or
* failure outcomes.
*/
export interface Resultant<T, E> {
/**
* Returns `x` if this result is {@link Ok}, otherwise returns the {@link Err}
* value of self.
*
* @example
* ```ts
* const x = ok<number, string>(1);
* const y = ok<number, string>(2);
* const z = err<number, string>("failure");
*
* expect(x.and(y)).toStrictEqual(ok(2));
* expect(x.and(z)).toStrictEqual(err("failure"));
* expect(z.and(x)).toStrictEqual(err("failure"));
* ```
*/
and<U>(x: Result<U, E>): Result<U, E>;
/**
* Applies `f` to the value if this result is {@link Ok} and returns its result,
* otherwise returns the {@link Err} value of self.
*
* @example
* ```ts
* const x = ok<number, string>(2);
* const y = err<number, string>("failure");
*
* expect(x.andThen(n => ok(n * 2))).toStrictEqual(ok(4));
* expect(y.andThen(n => ok(n * 2))).toStrictEqual(err("failure"));
* ```
*/
andThen<U>(f: (x: T) => Result<U, E>): Result<U, E>;
/**
* Inspects this result’s state, returning a tuple indicating success and either the value or error.
*
* @notes
* - Returns `[true, T]` if this is an {@link Ok}, or `[false, CheckedError<E>]`
* if this is an {@link Err}.
* - Never throws, providing a safe way to access the result’s state without
* unwrapping.
*
* @example
* ```ts
* const x = ok<number, string>(42);
* const y = err<number, string>("failure");
*
* expect(x.check()).toEqual([true, 42]);
* expect(y.check()).toEqual([false, expect.objectContaining({ expected: "failure" })]);
* ```
*/
check(this: SettledResult<T, E>): this extends Ok<T, E> ? readonly [true, T] : readonly [false, CheckedError<E>];
/**
* Returns a clone of the {@link Result}.
*
* Only available on {@link Result}s with {@link Cloneable} value and error.
*
* @example
* ```ts
* const x = ok(1);
* const y = ok({ a: 1, clone: () => ({ a: 0 }) });
*
* expect(x.clone()).toStrictEqual(ok(1));
* expect(x.clone()).not.toBe(x); // Different reference
* expect(x.clone().unwrap()).toBe(1);
* expect(y.clone()).toStrictEqual(ok({ a: 0 }));
* ```
*/
clone<U, F>(this: Result<Cloneable<U>, Cloneable<F>>): Result<U, F>;
/**
* Combines this {@link Result} with other `Result` instances into a single
* `Result` containing a tuple of values.
*
* The `combine` method takes an arbitrary number of `Result` instances,
* all sharing the same {@link Err} type. If all `Result` instances
* (including this one) are {@link Ok}, it returns a `Result` with a tuple of
* their `Ok` values in the order provided. If any `Result` is `Err`, it returns
* that `Err`. The resulting tuple includes the value of this `Result` as the first
* element, followed by the values from the provided `Result` instances.
*
* @example
* ```ts
* const a = ok<Promise<number>, string>(Promise.resolve(1));
* const b = ok<string, string>("hi");
* const c = err<Date, string>("no");
* const d = a.combine(b, c); // Result<[Promise<number>, string, Date], string>
* ```
*/
combine<U extends Result<unknown, E>[]>(...results: U): Result<[T, ...OkValues<U>], E>;
/**
* Returns a **shallow** copy of the {@link Result}.
*
* @example
* ```ts
* const value = { a: 1 };
* const x = ok<{ a: number }, string>(value);
*
* expect(x.copy()).toStrictEqual(ok({ a: 1 }));
* expect(x.copy()).not.toBe(x); // Different result reference
* expect(x.copy().unwrap()).toBe(value); // Same value reference
* ```
*/
copy(): Result<T, E>;
/**
* Converts this {@link Result} to an {@link Option | Option\<E>} containing
* the error, if present.
*
* Returns {@link Some} with the error value if this is an {@link Err}, or
* {@link None} if this is an {@link Ok}.
*
* @notes
* - Extracts the error from {@link CheckedError} if it’s an {@link ExpectedError};
* returns {@link None} for {@link UnexpectedError}.
*
* @example
* ```ts
* const x = ok<number, string>(1);
* const y = err<number, string>("failure");
*
* expect(x.err()).toStrictEqual(none());
* expect(y.err()).toStrictEqual(some("failure"));
* ```
*/
err(this: SettledResult<T, E>): Option<E>;
/**
* Retrieves the value if this result is an {@link Ok}, or throws a
* {@link ResultError} with an optional message if it’s an {@link Err}.
*
* @throws
* - {@link ResultError} if this result is an {@link Err}
*
* @example
* ```ts
* const x = ok<number, string>(42);
* const y = err<number, string>("failure");
*
* expect(x.expect("Failed!")).toBe(42);
* expect(() => y.expect("Failed!")).toThrow(ResultError);
* ```
*/
expect(this: SettledResult<T, E>, msg?: string): T;
/**
* Retrieves the error if this result is an {@link Err}, or throws a
* {@link ResultError} with an optional message if it’s an {@link Ok}.
*
* @throws
* - {@link ResultError} if this result is an {@link Ok}
*
* @example
* ```ts
* const x = ok<number, string>(42);
* const y = err<number, string>("failure");
*
* expect(() => x.expectErr("Failed!")).toThrow(ResultError);
* expect(isCheckedError(y.expectErr("Failed!"))).toBe(true);
* expect(y.expectErr("Failed!").expected).toBe("failure");
* ```
*/
expectErr(this: SettledResult<T, E>, msg?: string): CheckedError<E>;
/**
* Flattens a nested result (`Result<Result<T, E>, E>`) into a single result
* (`Result<T, E>`).
*
* @example
* ```ts
* const x: Result<Result<Result<number, string>, string>, string> = ok(ok(ok(6)));
* const y: Result<Result<number, string>, string> = x.flatten();
* const z: Result<Result<number, string>, string> = err("oops");
*
* expect(x.flatten()).toStrictEqual(ok(ok(6)));
* expect(y.flatten()).toStrictEqual(ok(6));
* expect(z.flatten().expected).toBe("oops");
* ```
*/
flatten<U, F>(this: Result<Result<U, F>, F>): Result<U, F>;
/**
* Calls `f` with the value if this result is an {@link Ok}, then returns
* a copy of this result.
*
* @notes
* - Returns a new {@link Result} instance, not the original reference.
* - If `f` throws or returns a `Promise` that rejects, the error is ignored.
*
* @example
* ```ts
* const x = ok<number, string>(2);
* const y = err<number, string>("failure");
* let sideEffect = 0;
*
* expect(x.inspect(n => (sideEffect = n))).toStrictEqual(ok(2));
* expect(x.inspect(_ => { throw new Error() })).toStrictEqual(ok(2));
* expect(sideEffect).toBe(2);
* expect(y.inspect(n => (sideEffect = n))).toStrictEqual(err("failure"));
* expect(sideEffect).toBe(2); // Unchanged
* ```
*/
inspect(f: (x: T) => unknown): Result<T, E>;
/**
* Calls `f` with the error if this result is an {@link Err}, then returns
* a copy of this result.
*
* @notes
* - Returns a new {@link Result} instance, not the original reference.
* - If `f` throws or returns a `Promise` that rejects, the error is ignored.
*
* @example
* ```ts
* const x = ok<number, string>(2);
* const y = err<number, string>("failure");
* let sideEffect = 0;
*
* expect(x.inspect(n => (sideEffect = n))).toStrictEqual(ok(2));
* expect(x.inspect(_ => { throw new Error() })).toStrictEqual(ok(2));
* expect(sideEffect).toBe(0);
* expect(y.inspect(n => (sideEffect = n))).toStrictEqual(err("failure"));
* expect(y.inspect(_ => { throw new Error() })).toStrictEqual(err("failure"));
* expect(sideEffect).toBe(2);
* ```
*/
inspectErr(f: (x: CheckedError<E>) => unknown): Result<T, E>;
/**
* Checks if this result is an {@link Err}, narrowing its type to
* {@link Err} if true.
*
* @example
* ```ts
* const x = ok<number, string>(2);
* const y = err<number, string>("failure");
*
* expect(x.isErr()).toBe(false);
* expect(y.isErr()).toBe(true);
* ```
*/
isErr(): this is Err<T, E>;
/**
* Returns `true` if the result is {@link Err} and `f` returns `true`
* for the contained error.
*
* @notes
* - *Default*: If `f` throws, `false` is returned.
*
* @example
* ```ts
* const x = ok<number, string>(2);
* const y = err<number, string>("failure");
*
* expect(x.isErrAnd(e => e.expected === "failure")).toBe(false);
* expect(y.isErrAnd(e => e.expected === "failure")).toBe(true);
* expect(y.isErrAnd(e => Boolean(e.unexpected))).toBe(false);
* ```
*/
isErrAnd(f: (x: CheckedError<E>) => boolean): this is Err<T, E> & boolean;
/**
* Checks if this result is an {@link Ok}, narrowing its type to
* {@link Ok} if true.
*
* @example
* ```ts
* const x = ok<number, string>(2);
* const y = err<number, string>("failure");
*
* expect(x.isOk()).toBe(true);
* expect(y.isOk()).toBe(false);
* ```
*/
isOk(): this is Ok<T, E>;
/**
* Returns `true` if the result is {@link Ok} and `f` returns `true`
* for the contained value.
*
* @notes
* - *Default*: If `f` throws, `false` is returned.
*
* @example
* ```ts
* const x = ok<number, string>(2);
* const y = err<number, string>("failure");
*
* expect(x.isOkAnd(n => n > 0)).toBe(true);
* expect(x.isOkAnd(n => n < 0)).toBe(false);
* expect(y.isOkAnd(_ => true)).toBe(false);
* ```
*/
isOkAnd(f: (x: T) => boolean): this is Ok<T, E> & boolean;
/**
* Returns an iterator over this result’s value, yielding it if {@link Ok}
* or nothing if {@link Err}.
*
* @notes
* - Yields exactly one item for {@link Ok}, or zero items for {@link Err}.
* - Compatible with `for...of` loops and spread operators.
* - Ignores the error value in {@link Err} cases, focusing only on the success case.
*
* @example
* ```ts
* const x = ok<number, string>(42);
* const y = err<number, string>("failure");
*
* 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>;
/**
* Transforms this result by applying `f` to the value if it’s an {@link Ok},
* or preserves the {@link Err} unchanged.
*
* @notes
* - If `f` throws, returns an {@link Err} with an {@link UnexpectedError}
* containing the original error.
*
* @example
* ```ts
* const x = ok<number, string>(2);
* const y = err<number, string>("failure");
*
* expect(x.map(n => n * 2)).toStrictEqual(ok(4));
* expect(x.map(() => { throw new Error("boom") }).unwrapErr().unexpected).toBeDefined();
* expect(y.map(n => n * 2)).toStrictEqual(err("failure"));
* ```
*/
map<U>(f: (x: T) => Awaited<U>): Result<U, E>;
/**
* Maps this result by applying a callback to its full state, executing the
* callback for both {@link Ok} and {@link Err}, returning a new {@link Result}.
*
* Unlike {@link Resultant.andThen | andThen}, which only invokes the callback
* for {@link Ok}, this method always calls `f`, passing the entire {@link Result}
* as its argument.
*
* @notes
* - If `f` throws an {@link Err} with an {@link UnexpectedError} is returned.
*
* @example
* ```ts
* const okRes = ok<number, string>(42);
* const errRes = err<number, string>("failure");
*
* expect(okRes.mapAll(res => ok(res.unwrapOr(0) + 1))).toStrictEqual(ok(43));
* expect(errRes.mapAll(res => ok(res.unwrapOr(0) + 1))).toStrictEqual(ok(1));
* expect(okRes.mapAll(res => res.isOk() ? ok("success") : err("fail"))).toStrictEqual(ok("success"));
* expect(errRes.mapAll(() => { throw new Error("boom") }).unwrapErr().unexpected).toBeDefined();
* ```
*/
mapAll<U, F>(f: (x: Result<T, E>) => Result<U, F>): Result<U, F>;
/**
* Maps this result by applying a callback to its full state, executing the
* callback for both {@link Ok} and {@link Err}, returning a new
* {@link PendingResult}.
*
* Unlike {@link Resultant.andThen | andThen}, which only invokes the callback
* for {@link Ok}, this method always calls `f`, passing the entire
* {@link Result} as its argument.
*
* @notes
* - If `f` returns a `Promise` that rejects, the resulting {@link PendingResult}
* resolves to an {@link Err} with an {@link UnexpectedError}.
*
* @example
* ```ts
* const okRes = ok<number, string>(42);
* const errRes = err<number, string>("failure");
*
* const mappedOk = okRes.mapAll(res => Promise.resolve(ok(res.unwrapOr(0) + 1)));
* expect(await mappedOk).toStrictEqual(ok(43));
*
* const mappedErr = errRes.mapAll(res => Promise.resolve(ok(res.unwrapOr(0) + 1)));
* expect(await mappedErr).toStrictEqual(ok(1));
*
* const mappedCheck = okRes.mapAll(res => Promise.resolve(res.isOk() ? ok("success") : err("fail")));
* expect(await mappedCheck).toStrictEqual(ok("success"));
*
* const mappedThrow = errRes.mapAll(() => Promise.reject(new Error("boom")));
* expect((await mappedThrow).unwrapErr().unexpected).toBeDefined();
* ```
*/
mapAll<U, F>(f: (x: Result<T, E>) => Promise<Result<U, F>>): PendingResult<Awaited<U>, Awaited<F>>;
/**
* Transforms this result by applying `f` to the error if it’s an {@link Err}
* with an expected error, or preserves the result unchanged.
*
* @notes
* - If `f` throws, returns an {@link Err} with an {@link UnexpectedError}
* containing the original error.
* - If this is an {@link Err} with an {@link UnexpectedError}, `f` is not called,
* and the original error is preserved.
*
* @example
* ```ts
* const x = ok<number, string>(2);
* const y = err<number, string>("failure");
*
* expect(x.mapErr(e => e.length)).toStrictEqual(ok(2));
* expect(y.mapErr(e => e.length)).toStrictEqual(err(7));
* expect(y.mapErr(() => { throw new Error("boom") }).unwrapErr().unexpected).toBeDefined();
* ```
*/
mapErr<F>(f: (e: E) => Awaited<F>): Result<T, F>;
/**
* Returns `f` applied to the value if {@link Ok}, otherwise returns `def`.
*
* @notes
* - *Default*: If `f` throws, returns `def`.
*
* @example
* ```ts
* const x = ok<number, string>(2);
* const y = err<number, string>("failure");
*
* expect(x.mapOr(0, n => n * 2)).toBe(4);
* expect(x.mapOr(0, () => { throw new Error("boom"); })).toBe(0);
* expect(y.mapOr(0, n => n * 2)).toBe(0);
* ```
*/
mapOr<U>(this: SettledResult<T, E>, def: Awaited<U>, f: (x: T) => Awaited<U>): U;
/**
* Returns `f` applied to the contained value if {@link Ok}, otherwise
* returns the result of `mkDef`.
*
* @throws
* - {@link ResultError} if `mkDef` is called and throws an exception, with
* the original error set as {@link ResultError.reason}.
*
* @notes
* - If `f` throws, the error is silently ignored, and the result of `mkDef`
* is returned.
*
* @example
* ```ts
* const x = ok<number, string>(2);
* const y = err<number, string>("failure");
*
* expect(x.mapOrElse(() => 0, n => n * 2)).toBe(4);
* expect(x.mapOrElse(() => 1, () => { throw new Error("boom") })).toBe(1);
* expect(() => y.mapOrElse(() => { throw new Error("boom") }, n => n * 2)).toThrow(ResultError);
* expect(y.mapOrElse(() => 0, n => n * 2)).toBe(0);
* ```
*/
mapOrElse<U>(this: SettledResult<T, E>, mkDef: () => Awaited<U>, f: (x: T) => Awaited<U>): U;
/**
* Matches this result, returning `f` applied to the value if {@link Ok},
* or `g` applied to the {@link CheckedError} if {@link Err}.
*
* @throws
* - {@link ResultError} if `f` or `g` throws an exception, with the original
* error set as {@link ResultError.reason}.
*
* @notes
* - If `f` or `g` return a `Promise` that rejects, the caller is responsible
* for handling the rejection.
*
* @example
* ```ts
* const x = ok<number, string>(2);
* const y = err<number, string>("failure");
*
* expect(x.match(n => n * 2, () => 0)).toBe(4);
* expect(() => x.match(_ => { throw new Error() }, () => 0)).toThrow(ResultError);
* expect(y.match(n => n * 2, e => e.expected?.length)).toBe(7);
* expect(() => y.match(n => n * 2, () => { throw new Error() })).toThrow(ResultError);
* ```
*/
match<U, F = U>(this: SettledResult<T, E>, f: (x: T) => Awaited<U>, g: (e: CheckedError<E>) => Awaited<F>): U | F;
/**
* Converts this result to an {@link Option}, discarding the error if present.
*
* Maps {@link Ok | Ok(v)} to {@link Some | Some(v)} and {@link Err | Err(e)}
* to {@link None}.
*
* @example
* ```ts
* const x = ok<number, string>(2);
* const y = err<number, string>("failure");
*
* expect(x.ok()).toStrictEqual(some(2));
* expect(y.ok()).toStrictEqual(none());
* ```
*/
ok(): Option<T>;
/**
* Returns the current result if it is {@link Ok}, otherwise returns `x`.
*
* @example
* ```ts
* const x = ok<number, string>(2);
* const y = err<number, string>("failure");
*
* expect(x.or(ok(3))).toStrictEqual(ok(2));
* expect(x.or(err("failure"))).toStrictEqual(ok(2));
* expect(y.or(ok(3))).toStrictEqual(ok(3));
* expect(y.or(err("another one"))).toStrictEqual(err("another one"));
* ```
*/
or<F>(x: Result<T, F>): Result<T, F>;
/**
* Returns the current result if {@link Ok}, otherwise returns the result of `f`.
*
* @notes
* - If `f` throws, returns an {@link Err} with an {@link UnexpectedError}
* containing the original error.
*
* @example
* ```ts
* const x = ok<number, string>(2);
* const y = err<number, string>("failure");
*
* expect(x.orElse(() => ok(3))).toStrictEqual(ok(2));
* expect(y.orElse(() => ok(3))).toStrictEqual(ok(3));
* expect(y.orElse(() => { throw new Error("boom") }).unwrapErr().unexpected).toBeDefined();
* expect(y.orElse(() => err("another one"))).toStrictEqual(err("another one"));
* ```
*/
orElse<F>(f: () => Result<T, F>): Result<T, F>;
/**
* Executes `f` with a copy of this result, then returns a new copy unchanged.
*
* Useful for side-effects like logging, works with both {@link Ok} and {@link Err}.
*
* @notes
* - If `f` throws or rejects, the error is silently ignored.
* - If `f` returns a promise, the promise is not awaited before returning.
*
* @example
* ```ts
* const x = ok<number, string>(42);
* const y = err<number, string>("failure");
* let log = "";
*
* expect(x.tap(res => (log = res.toString()))).toStrictEqual(ok(42));
* expect(log).toBe("Ok { 42 }");
* expect(y.tap(res => (log = res.toString()))).toStrictEqual(err("failure"));
* expect(log).toBe("Err { 'failure' }");
* ```
*/
tap(f: (x: Result<T, E>) => unknown): Result<T, E>;
/**
* Converts this result to a {@link PendingResult} using a shallow
* {@link Resultant.copy | copy} of its current state.
*
* @notes
* - Useful for transposing a result with a `PromiseLike` value to
* a {@link PendingResult} with an `Awaited` value.
*
* @example
* ```ts
* const value = { a: 1 };
* const x = ok<{ a: number }, string>(value);
* const pendingX = x.toPending();
*
* expect(isPendingResult(pendingX)).toBe(true);
* expect(await pendingX).toStrictEqual(ok({ a: 1 }));
* value.a = 2;
* expect(await pendingX).toStrictEqual(ok({ a: 2 }));
* ```
*/
toPending(): PendingResult<Awaited<T>, Awaited<E>>;
/**
* Converts this result to a {@link PendingResult} using a deep
* {@link Resultant.clone | clone} of its current state.
*
* @notes
* - Useful for transposing a result with a `PromiseLike` value to
* a {@link PendingResult} with an `Awaited` value, preserving independence
* from the original data.
* - If inner `T` or `E` is a promise-like that rejects, maps to a {@link PendingResult}
* that resolves to {@link Err} with {@link UnexpectedError}.
*
* @example
* ```ts
* const value = { a: 1, clone: () => ({ a: 0 }) };
* const x = ok(value);
* const pendingX = x.toPendingCloned();
*
* expect(isPendingResult(pendingX)).toBe(true);
* expect((await pendingX).unwrap()).toStrictEqual({ a: 0 });
* value.a = 42;
* expect((await pendingX).unwrap()).toStrictEqual({ a: 0 });
* ```
*/
toPendingCloned(this: Result<Cloneable<T>, Cloneable<E>>): PendingResult<Awaited<T>, Awaited<E>>;
/**
* Generates a string representation of this result,
* reflecting its current state.
*
* @example
* ```ts
* const x = ok<number, string>(2);
* const y = err<number, string>("error");
*
* expect(x.toString()).toBe("Ok { 2 }");
* expect(y.toString()).toBe("Err { 'error' }");
* ```
*/
toString(): string;
/**
* Transposes a {@link Result} of an {@link Option} into an {@link Option}
* of a {@link Result}.
*
* Maps `Ok(None)` to `None`, `Ok(Some(_))` to `Some(Ok(_))` and
* `Err(_)` to `Some(Err(_))`.
*
* @example
* ```ts
* const x = ok<Option<number>, string>(none());
* const y = ok<Option<number>, string>(some(2));
* const z = err<Option<number>, string>("error");
*
* expect(x.transpose()).toStrictEqual(none());
* expect(y.transpose()).toStrictEqual(some(ok(2)));
* expect(z.transpose()).toStrictEqual(some(err("error")));
* ```
*/
transpose<U, F>(this: Result<Option<U>, F>): Option<Result<U, F>>;
/**
* Extracts this result’s state, returning a tuple with a success flag, error,
* and value.
*
* Inspired by the {@link https://github.com/arthurfiorette/proposal-try-operator Try Operator}
* proposal.
*
* @notes
* - Returns `[true, undefined, T]` if this is an {@link Ok}, or
* `[false, CheckedError<E>, undefined]` if this is an {@link Err}.
* - Never throws, offering a safe way to inspect the result’s state with
* explicit success indication.
*
* @example
* ```ts
* const x = ok<number, string>(42);
* const y = err<number, string>("failure");
*
* expect(x.try()).toEqual([true, undefined, 42]);
* expect(y.try()).toEqual([false, expect.objectContaining({ expected: "failure" }), undefined]);
* ```
*/
try(this: SettledResult<T, E>): this extends Ok<T, E> ? readonly [true, undefined, T] : readonly [false, CheckedError<E>, undefined];
/**
* Retrieves the value if this result is an {@link Ok}, or throws
* a {@link ResultError} if it’s an {@link Err}.
*
* @throws
* - {@link ResultError} if this result is an {@link Err}
*
* @example
* ```ts
* const x = ok<number, string>(42);
* const y = err<number, string>("failure");
*
* expect(x.unwrap()).toBe(42);
* expect(() => y.unwrap()).toThrow(ResultError);
* ```
*/
unwrap(this: SettledResult<T, E>): T;
/**
* Retrieves the {@link CheckedError} if this result is an {@link Err}, or
* throws a {@link ResultError} if it’s an {@link Ok}.
*
* @throws
* - {@link ResultError} if this result is an {@link Ok}
*
* @example
* ```ts
* const x = ok<number, string>(42);
* const y = err<number, string>("failure");
*
* expect(() => x.unwrapErr()).toThrow(ResultError);
* expect(y.unwrapErr().expected).toBe("failure");
* ```
*/
unwrapErr(this: SettledResult<T, E>): CheckedError<E>;
/**
* Returns the contained value if {@link Ok}, or `def` if {@link Err}.
*
* @example
* ```ts
* const x = ok<number, string>(2);
* const y = err<number, string>("failure");
*
* expect(x.unwrapOr(0)).toBe(2);
* expect(y.unwrapOr(0)).toBe(0);
* ```
*/
unwrapOr(this: SettledResult<T, E>, def: Awaited<T>): T;
/**
* Returns the contained value if {@link Ok}, or the result of `mkDef`
* if {@link Err}.
*
* @throws
* - {@link ResultError} if `mkDef` throws, with the original error set as
* {@link ResultError.reason}.
*
* @example
* ```ts
* const x = ok<number, string>(2);
* const y = err<number, string>("failure");
*
* expect(x.unwrapOrElse(() => 0)).toBe(2);
* expect(y.unwrapOrElse(() => 0)).toBe(0);
* expect(() => y.unwrapOrElse(() => { throw new Error("boom") })).toThrow(ResultError);
* ```
*/
unwrapOrElse(this: SettledResult<T, E>, mkDef: () => Awaited<T>): T;
}
/**
* Interface defining an asynchronous {@link Result} that wraps a `Promise`
* resolving to a {@link Result}.
*
* Extends {@link Result} functionality for pending states, with methods mirroring
* their synchronous counterparts but returning {@link PendingResult} or `Promise`
* for async operations. Rejections typically resolve to {@link Err} unless otherwise
* specified.
*/
export interface PendingResult<T, E> extends PromiseLike<Result<T, E>>, Recoverable<Result<T, E>> {
/**
* Returns a {@link PendingResult} that resolves to {@link Err} if this result
* resolves to {@link Err}, otherwise returns a {@link PendingResult} with `x`.
*
* This is the asynchronous version of {@link Resultant.and | and}.
*
* @example
* ```ts
* const x = ok<number, string>(1).toPending();
* const y = ok<number, string>(2);
* const z = err<number, string>("failure").toPending();
*
* expect(await x.and(y)).toStrictEqual(ok(2));
* expect(await x.and(z)).toStrictEqual(err("failure"));
* expect(await z.and(x)).toStrictEqual(err("failure"));
* ```
*/
and<U>(x: Result<U, E> | PendingResult<U, E> | Promise<Result<U, E>>): PendingResult<Awaited<U>, Awaited<E>>;
/**
* Returns a {@link PendingResult} that resolves to {@link Err} if this result
* resolves to {@link Err}, otherwise applies `f` to the resolved {@link Ok}
* value and returns its result.
*
* This is the asynchronous version of {@link Resultant.andThen | andThen}.
*
* @example
* ```ts
* const x = ok<number, string>(2).toPending();
* const y = err<number, string>("failure").toPending();
*
* expect(await x.andThen(n => ok(n * 2))).toStrictEqual(ok(4));
* expect(await x.andThen(_ => err("oops"))).toStrictEqual(err("oops"));
* expect(await y.andThen(_ => err("oops"))).toStrictEqual(err("failure"));
* ```
*/
andThen<U>(f: (x: T) => Result<U, E> | PendingResult<U, E> | Promise<Result<U, E>>): PendingResult<Awaited<U>, Awaited<E>>;
/**
* Inspects this {@link PendingResult}’s state, returning a promise of
* a tuple with a success flag and either the value or error.
*
* This is the asynchronous version of {@link Resultant.check | check}.
*
* @notes
* - Resolves to `[true, Awaited<T>]` if this is an {@link Ok}, or to
* `[false, CheckedError<Awaited<E>>]` if this is an {@link Err}.
* - Never rejects, providing a safe way to await the result’s state.
*
* @example
* ```ts
* const x = ok<number, string>(42).toPending();
* const y = err<number, string>("failure").toPending();
*
* expect(await x.check()).toEqual([true, 42]);
* expect(await y.check()).toEqual([false, expect.objectContaining({ expected: "failure" })]);
* ```
*/
check(): Promise<readonly [boolean, Awaited<T> | CheckedError<Awaited<E>>]>;
/**
* Combines this {@link PendingResult} with other {@link Result} or `PendingResult`
* instances into a single `PendingResult` containing a tuple of resolved values.
*
* The `combine` method takes an arbitrary number of `Result` or `PendingResult`
* instances. It resolves all inputs and returns a `PendingResult` that, when
* resolved, contains a `Result` with a tuple of their {@link Ok} values if all
* resolve to `Ok`. If any input resolves to {@link Err}, the result resolves to
* that `Err`. The resulting tuple includes the resolved value of this `PendingResult`
* as the first element, followed by the resolved values from the provided instances.
*
* @example
* ```ts
* const a = pendingOk<number, Error>(1);
* const b = ok<Promise<string>, Error>(Promise.resolve("hi"));
* const c = err<symbol, Error>(new Error("An error occurred"));
* const d = pendingErr<Promise<Date>, Error>(new Error("not a date"));
* const e = a.combine(b, c, d); // PendingResult<[number, string, symbol, Date], Error>
* ```
*/
combine<U extends (Result<unknown, E> | PendingResult<unknown, E>)[]>(...opts: U): PendingResult<[Awaited<T>, ...OkAwaitedValues<U>], E>;
/**
* Converts this {@link PendingResult} to a {@link PendingOption | PendingOption\<E>}
* containing the awaited error, if present.
*
* Returns a {@link PendingOption} that resolves to {@link Some} with the error
* value if this resolves to an {@link Err} with {@link ExpectedError},
* or to {@link None} if this resolves to an {@link Ok} or {@link Err} with
* {@link UnexpectedError}.
*
* This is the asynchronous version of {@link Resultant.err | err}.
*
* @example
* ```ts
* const x = ok<number, string>(1).toPending();
* const y = err<number, string>("failure").toPending();
*
* expect(await x.err()).toStrictEqual(none());
* expect(await y.err()).toStrictEqual(some("failure"));
* ```
*/
err(): PendingOption<Awaited<E>>;
/**
* Flattens a nested {@link PendingResult} into a single pending result,
* resolving any inner {@link Result} or {@link PendingResult} to its final state.
*
* This is the asynchronous version of {@link Resultant.flatten | flatten}.
*
* @notes
* - Handles cases like `PendingResult<Result<T, E>, E>` or
* `PendingResult<PendingResult<T, E>, E>`, resolving to
* `PendingResult<Awaited<T>, Awaited<E>>`.
*
* @example
* ```ts
* const x = ok(ok(6)).toPending();
* const y = ok(err<number, string>("oops")).toPending();
*
* expect(await x.flatten()).toStrictEqual(ok(6));
* expect(await y.flatten()).toStrictEqual(err("oops"));
* ```
*/
flatten<U, F>(this: PendingResult<Result<U, F>, F> | PendingResult<PendingResult<U, F>, F> | PendingResult<PromiseLike<Result<U, F>>, F>): PendingResult<Awaited<U>, Awaited<F>>;
/**
* Calls `f` with the value if this pending result resolves to an {@link Ok},
* then returns a new pending result with the original state.
*
* This is the asynchronous version of {@link Resultant.inspect | inspect}.
*
* @notes
* - Returns a new {@link PendingResult} instance, not the original reference.
* - If `f` throws or returns a `Promise` that rejects, the error is ignored,
* and the returned promise still resolves to the original state.
*
* @example
* ```ts
* const x = ok<number, string>(2).toPending();
* const y = err<number, string>("failure").toPending();
* let sideEffect = 0;
*
* expect(await x.inspect(n => (sideEffect = n))).toStrictEqual(ok(2));
* expect(await x.inspect(_ => { throw new Error() })).toStrictEqual(ok(2));
* expect(sideEffect).toBe(2);
* expect(await y.inspect(n => (sideEffect = n))).toStrictEqual(err("failure"));
* expect(sideEffect).toBe(2); // Unchanged
* ```
*/
inspect(f: (x: T) => unknown): PendingResult<T, E>;
/**
* Calls `f` with the error if this pending result resolves to an {@link Err},
* then returns a new pending result with the original state.
*
* This is the asynchronous version of {@link Resultant.inspectErr | inspectErr}.
*
* @notes
* - Returns a new {@link PendingResult} instance, not the original reference.
* - If `f` throws or returns a `Promise` that rejects, the error is ignored,
* and the returned promise still resolves to the original state.
*
* @example
* ```ts
* const x = ok<number, string>(2).toPending();
* const y = err<number, string>("failure").toPending();
* let sideEffect: CheckedError<string> | null = null;
*
* expect(await x.inspectErr(n => (sideEffect = n))).toStrictEqual(ok(2));
* expect(await x.inspectErr(_ => { throw new Error() })).toStrictEqual(ok(2));
* expect(sideEffect).toBeNull();
* expect(await y.inspectErr(n => (sideEffect = n))).toStrictEqual(err("failure"));
* expect(await y.inspectErr(_ => { throw new Error() })).toStrictEqual(err("failure"));
* expect(isCheckedError(sideEffect)).toBe(true);
* ```
*/
inspectErr(f: (x: CheckedError<E>) => unknown): PendingResult<T, E>;
/**
* Returns an async iterator over this pending result’s value, yielding it if
* it resolves to {@link Ok} or nothing if it resolves to {@link Err}.
*
* @notes
* - Yields exactly one item for a resolved {@link Ok}, or zero items
* for a resolved {@link Err}.
* - Compatible with `for await...of` loops and async spread operators (with caution).
* - Ignores the error value in {@link Err} cases, focusing only on the success case.
*
* @example
* ```ts
* const x = ok<number, string>(42).toPending();
* const y = err<number, string>("failure").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 PendingResult} with
* the result if {@link Ok}, or the original {@link Err} if {@link Err}.
*
* This is the asynchronous version of {@link Resultant.map | map}.
*
* @notes
* - If `f` throws or returns a rejected promise, returns a {@link PendingResult}
* with an {@link Err} containing an {@link UnexpectedError}.
*
* @example
* ```ts
* const x = ok<number, string>(2).toPending();
* const y = err<number, string>("failure").toPending();
*
* expect(await x.map(n => n * 2)).toStrictEqual(ok(4));
* expect((await x.map(() => { throw new Error("boom") })).unwrapErr().unexpected).toBeDefined();
* expect(await y.map(n => n * 2)).toStrictEqual(err("failure"));
* ```
*/
map<U>(f: (x: T) => U): PendingResult<Awaited<U>, Awaited<E>>;
/**
* Maps this pending result by applying a callback to its full state,
* executing the callback for both {@link Ok} and {@link Err}, returning
* a new {@link PendingResult}.
*
* Unlike {@link andThen}, which only invokes the callback for {@link Ok},
* this method always calls `f`, passing the entire {@link Result} as its argument.
*
* This is the asynchronous version of {@link Resultant.mapAll | mapAll}.
*
* @notes
* - If `f` throws or returns a `Promise` that rejects, the newly created
* {@link PendingResult} will resolve to an {@link Err} with
* an {@link UnexpectedError}.
*
* @example
* ```ts
* const okRes = ok<number, string>(42).toPending();
* const errRes = err<number, string>("failure").toPending();
*
* const okMapped = okRes.mapAll(res => Promise.resolve(ok(res.unwrapOr(0) + 1)));
* expect(await okMapped).toStrictEqual(ok(43));
*
* const errMapped = errRes.mapAll(res => Promise.resolve(ok(res.unwrapOr(0) + 1)));
* expect(await errMapped).toStrictEqual(ok(1));
*
* const throwMapped = okRes.mapAll(() => { throw new Error("boom") });
* expect((await throwMapped).unwrapErr().unexpected).toBeDefined();
* ```
*/
mapAll<U, F>(f: (x: Result<T, E>) => Result<U, F> | PendingResult<U, F> | Promise<Result<U, F>>): PendingResult<Awaited<U>, Awaited<F>>;
/**
* Transforms this pending result by applying `f` to the error if it resolves
* to an {@link Err} with an expected error, or preserves the {@link Ok} unchanged.
*
* This is the asynchronous version of {@link Resultant.mapErr | mapErr}.
*
* @notes
* - If `f` throws or returns a rejected promise, returns a {@link PendingResult}
* with an {@link Err} containing an {@link UnexpectedError}.
* - If this resolves to an {@link Err} with an {@link UnexpectedError}, `f`
* is not called, and the original error is preserved.
*
* @example
* ```ts
* const x = ok<number, string>(2).toPending();
* const y = err<number, string>("failure").toPending();
*
* expect(await x.mapErr(e => e.length)).toStrictEqual(ok(2));
* expect(await y.mapErr(e => e.length)).toStrictEqual(err(7));
* expect((await y.mapErr(() => { throw new Error("boom") })).unwrapErr().unexpected).toBeDefined();
* ```
*/
mapErr<F>(f: (x: E) => F): PendingResult<Awaited<T>, Awaited<F>>;
/**
* Matches this {@link PendingResult}, returning a promise of `f` applied to
* the value if it resolves to an {@link Ok}, or `g` applied to the error if
* it resolves to an {@link Err}.
*
* This is the asynchronous version of {@link Resultant.match | match}.
*
* @throws
* - Rejects {@link ResultError} if `f` or `g` throws an exception or rejects,
* original error will be set as {@link ResultError.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 = ok<number, string>(2).toPending();
* const y = err<number, string>("failure").toPending();
*
* expect(await x.match(n => n * 2, () => 0)).toBe(4);
* expect(await y.match(n => n * 2, e => e.expected?.length)).toBe(7);
* ```
*/
match<U, F = U>(f: (x: T) => U, g: (e: CheckedError<E>) => F): Promise<Awaited<U | F>>;
/**
* Returns this pending result if it resolves to an {@link Ok},
* otherwise returns `x`.
*
* This is the asynchronous version of {@link Resultant.or | or}.
*
* @notes
* - If this result resolves to an {@link Err} and `x` is a `Promise` that
* rejects, the resulting {@link PendingResult} resolves to an {@link Err}
* with an {@link UnexpectedError}.
*
* @example
* ```ts
* const x = ok<number, string>(2).toPending();
* const y = err<number, string>("failure").toPending();
*
* expect(await x.or(ok(3))).toStrictEqual(ok(2));
* expect(await x.or(err("another one"))).toStrictEqual(ok(2));
* expect(await y.or(ok(3))).toStrictEqual(ok(3));
* expect(await y.or(err("another one"))).toStrictEqual(err("failure"));
* expect((await y.or(Promise.reject(new Error("boom")))).unwrapErr().unexpected).toBeDefined();
* ```
*/
or<F>(x: Result<T, F> | PendingResult<T, F> | Promise<Result<T, F>>): PendingResult<Awaited<T>, Awaited<F>>;
/**
* Returns this {@link PendingResult} if it resolves to {@link Ok}, otherwise
* returns a {@link PendingResult} with the result of `f`.
*
* This is the asynchronous version of {@link Resultant.orElse | orElse}.
*
* @notes
* - If `f` throws or returns a rejected promise, the resulting
* {@link PendingResult} resolves to an {@link Err} with
* an {@link UnexpectedError}.
*
* @example
* ```ts
* const x = ok<number, string>(2).toPending();
* const y = err<number, string>("failure").toPending();
*
* expect(await x.orElse(() => ok(3))).toStrictEqual(ok(2));
* expect(await y.orElse(() => Promise.resolve(ok(3)))).toStrictEqual(ok(3));
* expect((await y.orElse(() => { throw new Error("boom") })).unwrapErr().unexpected).toBeDefined();
* expect(await y.orElse(() => err("another one"))).toStrictEqual(err("another one"));
* ```
*/
orElse<F>(f: () => Result<T, F> | PendingResult<T, F> | Promise<Result<T, F>>): PendingResult<Awaited<T>, Awaited<F>>;
/**
* Executes `f` with the resolved result, then returns a new {@link PendingResult}
* unchanged.
*
* This is the asynchronous version of {@link Resultant.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 = pendingResult(ok<number, string>(42));
* const y = pendingResult(err<number, string>("failure"));
* let log = "";
*
* expect(await x.tap(res => (log = res.toString()))).toStrictEqual(ok(42));
* expect(log).toBe("Ok { 42 }");
* expect(await y.tap(res => (log = res.toString()))).toStrictEqual(err("failure"));
* expect(log).toBe("Err { 'failure' }");
* ```
*/
tap(f: (x: Result<T, E>) => unknown): PendingResult<T, E>;
/**
* Transposes a {@link PendingResult} of an {@link Option} into
* a {@link PendingOption} containing a {@link Result}.
*
* This is the asynchronous version of {@link Resultant.transpose | transpose}.
*
* @example
* ```ts
* const x = pendingOption(some(ok(2)));
* const y = pendingOption(some(err("error")));
* const z = pendingOption(none<Result<number, string>>());
*
* expect(await x.transpose()).toStrictEqual(ok(some(2)));
* expect(await y.transpose()).toStrictEqual(err("error"));
* expect(await z.transpose()).toStrictEqual(ok(none()));
* ```
*/
transpose<U, F>(this: PendingResult<Option<U>, F>): PendingOption<Result<U, F>>;
/**
* Extracts this {@link PendingResult}’s state, returning a promise of a tuple
* with a success flag, error, and value.
*
* Inspired by the {@link https://github.com/arthurfiorette/proposal-try-operator Try Operator}
* proposal.
*
* This is the asynchronous version of {@link Resultant.try | try}.
*
* @notes
* - Resolves to `[true, undefined, Awaited<T>]` if this is an {@link Ok}, or
* `[false, CheckedError<Awaited<E>>, undefined]` if this is an {@link Err}.
* - Never rejects, offering a safe way to await the result’s state with
* explicit success indication.
*
* @example
* ```ts
* const x = ok<number, string>(42).toPending();
* const y = err<number, string>("failure").toPending();
*
* expect(await x.try()).toEqual([true, undefined, 42]);
* expect(await y.try()).toEqual([false, expect.objectContaining({ expected: "failure" }), undefined]);
* ```
*/
try(): Promise<readonly [
boolean,
CheckedError<Awaited<E>> | undefined,
Awaited<T> | undefined
]>;
}
//# sourceMappingURL=interface.d.ts.map