PendingResult
PendingResult represents a
Result, whose value is not yet resolved (thus, pending).
PendingResult implements PromiseLike<Result<T, E>> interface, which means that
it can be Awaited as a regular Promise.
In order to access the value of PendingResult, you need to await it, which
will resolve it to either Ok<T> or Err<E> variant. Once resolved, you can
use the methods available on Result to work with the value.
Constructors
pendingErr(error: E | CheckedError<E> | Promise<E> | Promise<CheckedError<E>>)- creates aPendingResultthat resolves toErr<E>variant.pendingOk(value: T | Promise<T>)- creates aPendingOptionthat resolves toSome<T>variant.pendingResult(resultOrFactory: | Result<T, E> | Promise<Result<T, E>> | (() => Result<T, E> | Promise<Result<T, E>>))- creates aPendingOptionthat resolves to the providedResult.
Methods
and
Returns a PendingResult that resolves to Err if this result resolves to Err,
otherwise returns a PendingResult with x.
This is the asynchronous version of and.
If x is a Promise and rejects, None is returned.
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"));
andThen
Returns a PendingResult that resolves to Err if this result resolves to Err,
otherwise applies f to the resolved Ok value and returns its result.
This is the asynchronous version of andThen.
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"));
check
check(): Promise<[boolean, Awaited<T> | CheckedError<Awaited<E>>]>
Inspects this 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 check.
- Resolves to
[true, Awaited<T>]if this is anOk, or to[false, CheckedError<Awaited<E>>]if this is anErr. - Never rejects, providing a safe way to await the result’s state.
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" })]);
combine
Combines this PendingResult with other 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 Ok values if all
resolve to Ok. If any input resolves to 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.
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>
err
err(): PendingOption<Awaited<E>>
Converts this PendingResult to a PendingOption containing the awaited error, if present.
Returns a PendingOption that resolves to Some
with the error value if this resolves to an Err with ExpectedError,
or to None if this resolves to an Ok
or Err with UnexpectedError.
This is the asynchronous version of err.
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"));
flatten
Flattens a nested PendingResult into a single pending result,
resolving any inner Result or PendingResult to its final state.
This is the asynchronous version of flatten.
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"));
inspect
inspect(f: (x: T) => unknown): PendingResult<T, E>
Calls f with the value if this pending result resolves to an Ok,
then returns a new pending result with the original state.
This is the asynchronous version of inspect.
- Returns a new
PendingResultinstance, not the original reference. - If
fthrows or returns aPromisethat rejects, the error is ignored, and the returned promise still resolves to the original state.
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
inspectErr
inspectErr(f: (x: CheckedError<E>) => unknown): PendingResult<T, E>
Calls f with the error if this pending result resolves to an Err,
then returns a new pending result with the original state.
This is the asynchronous version of inspectErr.
- Returns a new
PendingResultinstance, not the original reference. - If
fthrows or returns aPromisethat rejects, the error is ignored, and the returned promise still resolves to the original state.
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);
iter
iter(): AsyncIterableIterator<Awaited<T>, Awaited<T>, void>
Returns an async iterator over this pending result’s value, yielding it if
it resolves to Ok or nothing if it resolves to Err.
- Yields exactly one item for a resolved
Ok, or zero items for a resolvedErr. - Compatible with
for await...ofloops and async spread operators (with caution). - Ignores the error value in
Errcases, focusing only on the success case.
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: AsyncIterableIterator<number, number, void>) {
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([]);
map
map<U>(f: (x: T) => U): PendingResult<Awaited<U>, Awaited<E>>
Maps the resolved value with f, returning a PendingResult with
the result if Ok, or the original Err if Err.
This is the asynchronous version of map.
If f throws or returns a rejected promise, returns a PendingResult
with an Err containing an UnexpectedError.
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"));
mapAll
Maps this pending result by applying a callback to its full state,
executing the callback for both Ok and Err, returning
a new PendingResult.
Unlike andThen, which only invokes the callback for Ok,
this method always calls f, passing the entire Result as its argument.
This is the asynchronous version of mapAll.
If f throws or returns a Promise that rejects, the newly created PendingResult
will resolve to an Err with an UnexpectedError.
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();
mapErr
mapErr<F>(f: (x: E) => F): PendingResult<Awaited<T>, Awaited<F>>
Transforms this pending result by applying f to the error if it resolves
to an Err with an expected error, or preserves the Ok unchanged.
This is the asynchronous version of mapErr.
- If
fthrows or returns a rejected promise, returns aPendingResultwith anErrcontaining anUnexpectedError. - If this resolves to an
Errwith anUnexpectedError,fis not called, and the original error is preserved.
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();
match
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 Ok, otherwise returns x.
This is the asynchronous version of match.
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.
Rejects with ResultError if f or g throws an exception or rejects,
original error will be set as ResultError.reason.
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);
or
Returns this pending result if it resolves to an Ok, otherwise returns x.
This is the asynchronous version of or.
If this result resolves to an Err and x is a Promise that rejects, the resulting
PendingResult resolves to an Err with an UnexpectedError.
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();
orElse
Returns this PendingResult if it resolves to Ok, otherwise
returns a PendingResult with the result of f.
This is the asynchronous version of orElse.
If f throws or returns a rejected promise, the resulting PendingResult resolves
to an Err with an UnexpectedError.
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"));
tap
tap(f: (x: Result<T, E>) => unknown): PendingResult<T, E>
Executes f with the resolved result, then returns a new PendingResult unchanged.
This is the asynchronous version of tap.
- If
fthrows or rejects, the error is ignored. - If
freturns a promise, the promise is not awaited before returning.
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' }");
transpose
transpose<U, F>(this: PendingResult<Option<U>, F>): PendingOption<Result<U, F>>
Transposes a PendingResult of an Option into a PendingOption containing a Result.
This is the asynchronous version of transpose.
Only available when the PendingResult resolves to an Option.
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()));
try
try(): Promise<[boolean, CheckedError<Awaited<E>> | undefined, Awaited<T> | undefined]>
Extracts this PendingResult’s state, returning a promise of a tuple with a success flag, error, and value.
Inspired by the Try Operator proposal.
This is the asynchronous version of try.
- Resolves to
[true, undefined, Awaited<T>]if this is anOk, or[false, CheckedError<Awaited<E>>, undefined]if this is anErr. - Never rejects, offering a safe way to await the result’s state with explicit success indication.
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]);