Skip to content

Promise Result operators

Async operators — barrel export.

Re-exports all asynchronous operators for working with Promise<IResultOfT<T, E>> values.

For Promise<IOption<T>> operators, see ../promise-option/index.js (subpath ./promise-option).

Applicative ap for Promise<IResultOfT>. Applies a function wrapped in a Promise<IResultOfT> to a value wrapped in a Promise<IResultOfT>. If either is a failure, the first failure propagates.

Mirrors async-result/ap for promise-based pipelines.

export function ap<A, B, E>(
fnResult: Promise<IResultOfT<(a: A) => B, E>>,
): (result: Promise<IResultOfT<A, E>>) => Promise<IResultOfT<B, E>>;
export function ap<A, B, E>(
fnResult: Promise<IResultOfT<(a: A) => B, E>>,
result: Promise<IResultOfT<A, E>>,
): Promise<IResultOfT<B, E>>;

Defined in: promise-result/ap.ts

import { ap, asyncOk, asyncErr } from '@sandlada/result/promise-result';
await ap(asyncOk((x: number) => x * 2), asyncOk(21)); // Ok(42)
await ap(asyncOk((x: number) => x * 2), asyncErr('x')); // Err('x')

Chains a result-producing async function over a sync IResultOfT. The callback returns Promise<IResultOfT<B, F>>, and the result is wrapped into a Promise<IResultOfT<B, F>>.

Bridges from the sync result world to the async world — unlike bindAsync which works on Promise<IResultOfT>. Where bindAsync accepts callbacks that may return sync or async results, asyncBind requires an async callback.

Throw policy: a synchronous throw from f propagates via the outer promise rejection. A rejected Promise from f propagates as a rejection. Matches the canonical AsyncResult throw policy.

G14 type-lie fix: the previous signature returned Promise<IResultOfT<B, E | F>>, but the success path of the chain can never produce an E (the source E is only carried by the failure path, which short-circuits before f is invoked). The success path produced Promise<IResultOfT<B, F>> only. Additionally, the original used Promise.resolve().then(() => f(r.value)), which yields Promise<Promise<IResultOfT<B, F>>> — await on the outer result would yield a Promise that needs a second await to extract the result.

The fix:

  • Drop E from the success-path return type (E is only in the failure branch, handled by the line 43 short-circuit).
  • Use Promise.resolve(r.value).then(f) so the inner promise is properly unwrapped by the await chain.
export function asyncBind<A, B, F>(
f: (a: A) => Promise<IResultOfT<B, F>>,
): <E>(r: IResultOfT<A, E>) => Promise<IResultOfT<B, F>>;
export function asyncBind<A, B, E, F>(
f: (a: A) => Promise<IResultOfT<B, F>>,
r: IResultOfT<A, E>,
): Promise<IResultOfT<B, F>>;

Defined in: promise-result/asyncBind.ts

import { asyncBind } from '@sandlada/result/promise-result';
import { ok, err } from '@sandlada/result/factories';
const r = await asyncBind(async (x: number) => ok(x * 2), ok(21));
// Ok(42)
// Curried form:
const process = asyncBind(async (x: number) => x > 0 ? ok(x) : err('negative'));
const r2 = await process(ok(5));

Side-effect on the success track — calls an async function on success that can propagate errors. If fn returns a failure, that failure propagates. If fn returns a success, the original success value passes through unchanged.

The key difference from asyncBind is that asyncBindThrough preserves the original success value on success, while asyncBind replaces it.

Bridges from the sync result world to the async world — unlike bindAsync which works on Promise<IResultOfT>.

export function asyncBindThrough<A, B, F>(
fn: (a: A) => Promise<IResultOfT<B, F>>,
): <E>(r: IResultOfT<A, E>) => Promise<IResultOfT<A, E | F>>;
export function asyncBindThrough<A, B, E, F>(
fn: (a: A) => Promise<IResultOfT<B, F>>,
r: IResultOfT<A, E>,
): Promise<IResultOfT<A, E | F>>;

Defined in: promise-result/asyncBindThrough.ts

import { asyncBindThrough } from '@sandlada/result/promise-result';
import { ok, err } from '@sandlada/result/factories';
// Validate and preserve original value on success:
const r = await asyncBindThrough(
async (v: string) => v.length > 0 ? ok(v) : err('empty'),
ok('data'),
);
// Ok('data') if valid, Err('empty') if invalid

Transforms the success value of a sync IResultOfT using an async callback. The callback returns a Promise, and the result is wrapped into a Promise<IResultOfT>.

This bridges from the sync result world to the async world — unlike mapAsync which works on Promise<IResultOfT>.

export function asyncMap<A, B>(
f: (a: A) => Promise<B>,
): <E>(r: IResultOfT<A, E>) => Promise<IResultOfT<B, E>>;
export function asyncMap<A, B, E>(
f: (a: A) => Promise<B>,
r: IResultOfT<A, E>,
): Promise<IResultOfT<B, E>>;

Defined in: promise-result/asyncMap.ts

import { asyncMap } from '@sandlada/result/promise-result';
import { ok, err } from '@sandlada/result/factories';
import { pipe } from '@sandlada/result/composition';
const r = await asyncMap(async (x: number) => x * 2, ok(21));
// Ok(42)
// Curried form:
const doubled = asyncMap(async (x: number) => x * 2);
const r2 = await doubled(ok(21));

Async match for sync IResultOfT. Lifts a sync Result into the async world and pattern-matches with async-allowed handlers.

export function asyncMatch<T, E, U>(
handlers: { ok: (value: T) => U | Promise<U>; err: (error: E) => U | Promise<U> },
): (r: IResultOfT<T, E>) => Promise<U>;
export function asyncMatch<T, E, U>(
handlers: { ok: (value: T) => U | Promise<U>; err: (error: E) => U | Promise<U> },
r: IResultOfT<T, E>,
): Promise<U>;

Defined in: promise-result/asyncMatch.ts

import { asyncMatch } from '@sandlada/result/promise-result';
import { ok } from '@sandlada/result/factories';
await asyncMatch({ ok: async (x: number) => `got ${x}`, err: async (e: string) => `error: ${e}` }, ok(42)); // 'got 42'

Async orElse for sync IResultOfT. Lifts a sync Result into the async world and recovers from failure via an async callback.

Companion to asyncBind — asyncBind chains forward on Ok; asyncOrElse recovers on Err.

export function asyncOrElse<T, E, F>(
f: (e: E) => Promise<IResultOfT<T, F>>,
): (r: IResultOfT<T, E>) => Promise<IResultOfT<T, E | F>>;
export function asyncOrElse<T, E, F>(
f: (e: E) => Promise<IResultOfT<T, F>>,
r: IResultOfT<T, E>,
): Promise<IResultOfT<T, E | F>>;

Defined in: promise-result/asyncOrElse.ts

import { asyncOrElse } from '@sandlada/result/promise-result';
import { ok, err } from '@sandlada/result/factories';
await asyncOrElse(async (e: string) => ok(0), err('boom')); // Ok(0)
await asyncOrElse(async (e: string) => ok(0), ok(42)); // Ok(42)

Side-effect on success for a sync IResultOfT using an async callback. Returns the original Result. If the callback throws or returns a rejected Promise, the error is caught and returned as an Err result.

export function asyncTap<A, E>(
fn: (a: A) => Promise<void | unknown>,
): (r: IResultOfT<A, E>) => Promise<IResultOfT<A, E>>;
export function asyncTap<A, E>(
fn: (a: A) => Promise<void | unknown>,
r: IResultOfT<A, E>,
): Promise<IResultOfT<A, E>>;

Defined in: promise-result/asyncTap.ts

import { ok } from '@sandlada/result/factories';
import { asyncTap } from '@sandlada/result/promise-result';
const log = asyncTap(async (x: number) => { console.log(x); });
await log(ok(42)); // Ok(42) — side-effect only

Side-effect on failure for a sync IResultOfT using an async callback. Returns the original Result. If the callback throws or returns a rejected Promise, the error is caught and returned as an Err result.

export function asyncTapErr<A, E>(
fn: (e: E) => Promise<void | unknown>,
): (r: IResultOfT<A, E>) => Promise<IResultOfT<A, E>>;
export function asyncTapErr<A, E>(
fn: (e: E) => Promise<void | unknown>,
r: IResultOfT<A, E>,
): Promise<IResultOfT<A, E>>;

Defined in: promise-result/asyncTapErr.ts

import { err } from '@sandlada/result/factories';
import { asyncTapErr } from '@sandlada/result/promise-result';
const log = asyncTapErr(async (e: string) => { console.error(e); });
await log(err('oops')); // Err('oops') — side-effect only

Maps both success and failure values of a Promise<IResultOfT<A, E>> simultaneously.

export function bimapAsync<A, E, B, F>(
onOk: (a: A) => B | Promise<B>,
onErr: (e: E) => F | Promise<F>,
): (r: Promise<IResultOfT<A, E>>) => Promise<IResultOfT<B, F>>;
export function bimapAsync<A, E, B, F>(
onOk: (a: A) => B | Promise<B>,
onErr: (e: E) => F | Promise<F>,
r: Promise<IResultOfT<A, E>>,
): Promise<IResultOfT<B, F>>;

Defined in: promise-result/bimapAsync.ts

import { bimapAsync } from '@sandlada/result/promise-result';
import { ok } from '@sandlada/result/factories';
const r = await bimapAsync(
(x: number) => x.toString(),
(e: number) => e * 2,
Promise.resolve(ok(5)),
); // Ok('5')

Chains an async result-returning function. fn can return IResultOfT or Promise<IResultOfT>. The error type widens to E | F.

Throw policy: a synchronous throw from f propagates to the caller via the outer promise rejection (the .then handler re-throws). A rejected Promise from f propagates as a rejection. This matches the canonical AsyncResult throw policy (“sync throws and async rejections propagate”).

Compared to asyncBind: bindAsync works on a Promise<IResultOfT> (the source is async). asyncBind is the inverse — it works on a sync IResultOfT and lifts it into a Promise<IResultOfT> (the callback is async).

export function bindAsync<A, B, F>(
f: (a: A) => IResultOfT<B, F> | Promise<IResultOfT<B, F>>,
): <E>(r: Promise<IResultOfT<A, E>>) => Promise<IResultOfT<B, E | F>>;
export function bindAsync<A, B, E, F>(
f: (a: A) => IResultOfT<B, F> | Promise<IResultOfT<B, F>>,
r: Promise<IResultOfT<A, E>>,
): Promise<IResultOfT<B, E | F>>;

Defined in: promise-result/bindAsync.ts

import { bindAsync, asyncOk, asyncErr } from '@sandlada/result/promise-result';
await bindAsync(
(x: number) => x > 0 ? asyncOk(x * 2) : asyncErr('too small'),
asyncOk(21),
);

Side-effect on success for a Promise<IResultOfT> that can propagate errors.

Throw policy: through-family catch policy — a synchronous throw and a rejected Promise from fn both converge to Err(thrown), matching asyncBindThrough and the sync andThrough.

export function bindThroughAsync<A, B, F>(
fn: (a: A) => IResultOfT<B, F> | Promise<IResultOfT<B, F>>,
): <E>(r: Promise<IResultOfT<A, E>>) => Promise<IResultOfT<A, E | F>>;
export function bindThroughAsync<A, B, E, F>(
fn: (a: A) => IResultOfT<B, F> | Promise<IResultOfT<B, F>>,
r: Promise<IResultOfT<A, E>>,
): Promise<IResultOfT<A, E | F>>;

Defined in: promise-result/bindThroughAsync.ts

import { bindThroughAsync } from '@sandlada/result/promise-result';
import { ok } from '@sandlada/result/factories';
const validate = bindThroughAsync(async (x: number) =>
x > 0 ? ok(x) : Promise.reject(new Error('non-positive')),
);
const r = await validate(Promise.resolve(ok(5))); // Ok(5)

Async variant of catchErr for Promise<IResultOfT>.

Recovers from an error by returning a fallback value T (or a Promise resolving to T), automatically wrapping it in a resolved Ok(T).

Throw policy: Unlike tap/tapErr (which catch and convert to Err), catchErrAsync deliberately lets sync throws and async rejections from onErr propagate verbatim as Promise rejections. The recovery handler is the only escape hatch for an Err source — making it swallow its own failures would hide bugs that should surface. Wrap your recovery logic in try/catch locally if you need to swallow.

export function catchErrAsync<A, E>(
onErr: (e: E) => A | Promise<A>,
): (r: Promise<IResultOfT<A, E>>) => Promise<IResultOfT<A, never>>;
export function catchErrAsync<A, E>(
onErr: (e: E) => A | Promise<A>,
r: Promise<IResultOfT<A, E>>,
): Promise<IResultOfT<A, never>>;

Defined in: promise-result/catchErrAsync.ts

import { catchErrAsync, asyncErr } from '@sandlada/result/promise-result';
await catchErrAsync(async (e: string) => 0, asyncErr('boom')); // Ok(0)

Combines an array of Promise<IResultOfT> into a single Promise<IResultOfT<T[], E>>. Short-circuits on the first failure (like Promise.all).

Mirrors async-result/combine for promise-based pipelines.

export function combine<A, E>(
results: readonly Promise<IResultOfT<A, E>>[],
): Promise<IResultOfT<A[], E>>;

Defined in: promise-result/combine.ts

import { combine, asyncOk, asyncErr } from '@sandlada/result/promise-result';
await combine([asyncOk(1), asyncOk(2)]); // Ok([1, 2])
await combine([asyncOk(1), asyncErr('x')]); // Err('x')

Combines Promise<IResultOfT> accumulating all errors (validation aggregation). Unlike combine, this collects every error before failing.

Mirrors async-result/combineWithAllErrors.

export function combineWithAllErrors<A, E>(
results: readonly Promise<IResultOfT<A, E>>[],
): Promise<IResultOfT<A[], E[]>>;

Defined in: promise-result/combineWithAllErrors.ts

import { combineWithAllErrors, asyncOk, asyncErr } from '@sandlada/result/promise-result';
await combineWithAllErrors([asyncOk(1), asyncErr('a'), asyncErr('b')]); // Err(['a', 'b'])
await combineWithAllErrors([asyncOk(1), asyncOk(2)]); // Ok([1, 2])

Returns true if the Promise<IResultOfT> is success and contains the given value.

export function containsAsync<A>(
value: A,
): <E>(r: Promise<IResultOfT<A, E>>) => Promise<boolean>;
export function containsAsync<A, E>(
value: A,
r: Promise<IResultOfT<A, E>>,
): Promise<boolean>;

Defined in: promise-result/containsAsync.ts

import { containsAsync } from '@sandlada/result/promise-result';
import { ok } from '@sandlada/result/factories';
const r = await containsAsync(42, Promise.resolve(ok(42))); // true

Returns true if the Promise<IResultOfT> is success and the predicate holds. Returns false on failure or when the predicate does not hold.

Throw policy: If the predicate throws synchronously or returns a rejected Promise, the rejection propagates to the outer Promise (matches the canonical AsyncResult throw policy — “sync throws and async rejections propagate”). Use existsAsyncOption if you want predicate errors to convert to false.

export function existsAsync<A>(
predicate: (a: A) => boolean | Promise<boolean>,
): <E>(r: Promise<IResultOfT<A, E>>) => Promise<boolean>;
export function existsAsync<A, E>(
predicate: (a: A) => boolean | Promise<boolean>,
r: Promise<IResultOfT<A, E>>,
): Promise<boolean>;

Defined in: promise-result/existsAsync.ts

import { existsAsync } from '@sandlada/result/promise-result';
import { ok } from '@sandlada/result/factories';
const r = await existsAsync(async (x: number) => x > 10, Promise.resolve(ok(42)));
// true

Filters the success value of a Promise<IResultOfT<A, E>> with a predicate. If the predicate holds, the original success passes through. If it fails, returns err(errorFn(value)). Failures pass through unchanged.

Throw policy: A synchronous throw or rejected Promise from predicate or errorFn propagates to the outer Promise (matches the canonical AsyncResult throw policy — “sync throws and async rejections propagate”). The e as E cast that previously lived here has been removed; callers that need to capture thrown errors in the Err channel should wrap with tryCatch or similar.

export function filterOrElseAsync<A, E>(
predicate: (a: A) => boolean | Promise<boolean>,
errorFn: (a: A) => E | Promise<E>,
): (r: Promise<IResultOfT<A, E>>) => Promise<IResultOfT<A, E>>;
export function filterOrElseAsync<A, E>(
predicate: (a: A) => boolean | Promise<boolean>,
errorFn: (a: A) => E | Promise<E>,
r: Promise<IResultOfT<A, E>>,
): Promise<IResultOfT<A, E>>;

Defined in: promise-result/filterOrElseAsync.ts

import { filterOrElseAsync } from '@sandlada/result/promise-result';
import { ok } from '@sandlada/result/factories';
const r = await filterOrElseAsync(
(x: number) => x > 0,
(x: number) => `${x} is not positive`,
Promise.resolve(ok(5)),
); // Ok(5)

Strictly synchronous flatten over a Promise<IResultOfT<IResultOfT>>. Unwraps exactly one layer.

export function flatten<A, E>(
r: Promise<IResultOfT<IResultOfT<A, E>, E>>,
): Promise<IResultOfT<A, E>>;

Defined in: promise-result/flatten.ts

import { flatten } from '@sandlada/result/promise-result';
import { ok, err } from '@sandlada/result/factories';
await flatten(Promise.resolve(ok(ok(42)))); // Ok(42)
await flatten(Promise.resolve(ok(err('x')))); // Err('x')

Flattens a nested Promise<IResultOfT<IResultOfT<A, E>, E>>.

Single-step only: unwraps exactly one layer. Call flattenAsync repeatedly to flatten deeper nests.

export function flattenAsync<A, E>(
r: Promise<IResultOfT<IResultOfT<A, E>, E>>,
): Promise<IResultOfT<A, E>>;

Defined in: promise-result/flattenAsync.ts

import { flattenAsync } from '@sandlada/result/promise-result';
import { ok } from '@sandlada/result/factories';
const r = await flattenAsync(Promise.resolve(ok(ok(42)))); // Ok(42)
const r2 = await flattenAsync(Promise.resolve(ok(ok(ok(7))))); // Ok(ok(7))

Strictly synchronous map over a Promise<IResultOfT>. The mapper is required to be sync. Sync throws are caught and converted to err(caughtError). Async results from fn are not awaited.

For a callback that may be sync or async, prefer mapAsync.

export function map<A, B>(
f: (a: A) => B,
): <E>(r: Promise<IResultOfT<A, E>>) => Promise<IResultOfT<B, E>>;
export function map<A, B, E>(
f: (a: A) => B,
r: Promise<IResultOfT<A, E>>,
): Promise<IResultOfT<B, E>>;

Defined in: promise-result/map.ts

import { map, asyncOk, asyncErr } from '@sandlada/result/promise-result';
await map((x: number) => x * 2, asyncOk(21)); // Ok(42)
await map((x: number) => x * 2, asyncErr('boom')); // Err('boom')

Transforms the success value of a Promise<IResultOfT<A, E>>. The callback may be sync or async.

export function mapAsync<A, B>(
f: (a: A) => B | Promise<B>,
): <E>(r: Promise<IResultOfT<A, E>>) => Promise<IResultOfT<B, E>>;
export function mapAsync<A, B, E>(
f: (a: A) => B | Promise<B>,
r: Promise<IResultOfT<A, E>>,
): Promise<IResultOfT<B, E>>;

Defined in: promise-result/mapAsync.ts

import { mapAsync, asyncOk } from '@sandlada/result/promise-result';
await mapAsync((x: number) => x * 2, asyncOk(21)); // Ok(42)

Strictly synchronous mapErr over a Promise<IResultOfT>. The mapper is required to be sync. Sync throws are caught and converted to err(caughtError).

For a callback that may be sync or async, prefer mapErrAsync.

export function mapErr<A, E, F>(
f: (e: E) => F,
): <T>(r: Promise<IResultOfT<T, E>>) => Promise<IResultOfT<T, F>>;
export function mapErr<T, E, F>(
f: (e: E) => F,
r: Promise<IResultOfT<T, E>>,
): Promise<IResultOfT<T, F>>;

Defined in: promise-result/mapErr.ts

import { mapErr, asyncOk, asyncErr } from '@sandlada/result/promise-result';
await mapErr((e: string) => e.toUpperCase(), asyncErr('boom')); // Err('BOOM')
await mapErr((e: string) => e.toUpperCase(), asyncOk(42)); // Ok(42)

Transforms the error of a Promise<IResultOfT<A, E>>.

export function mapErrAsync<E, F>(
f: (e: E) => F | Promise<F>,
): <A>(r: Promise<IResultOfT<A, E>>) => Promise<IResultOfT<A, F>>;
export function mapErrAsync<A, E, F>(
f: (e: E) => F | Promise<F>,
r: Promise<IResultOfT<A, E>>,
): Promise<IResultOfT<A, F>>;

Defined in: promise-result/mapErrAsync.ts

import { mapErrAsync, asyncErr } from '@sandlada/result/promise-result';
await mapErrAsync((e: string) => `[wrapped] ${e}`, asyncErr('boom'));

Maps the success value of an async result, or returns defaultValue on failure. The mapping function may be sync or async. Equivalent to mapAsync(fn).then(unwrapOrAsync(defaultValue)) but more efficient.

Throw policy: if fn throws synchronously or its returned Promise<B> rejects, the result is defaultValue (not an Err). The thrown reason is discarded — use mapAsync(fn).then(unwrapOrElse(err)) if you need the reason.

The curried form accepts an optional onErr thunk that observes the rejected reason. Supplying onErr makes E inferable at the curried site, matching mapOrElseAsync’s inference behaviour. The error is still discarded — onErr exists purely for inference and side-effect observation, not for value substitution.

export function mapOrAsync<A, B, E>(
defaultValue: B,
fn: (a: A) => B | Promise<B>,
): <R extends Promise<IResultOfT<A, E>>>(r: R) => Promise<B>;
export function mapOrAsync<A, B, E>(
defaultValue: B,
fn: (a: A) => B | Promise<B>,
onErr: (e: E) => unknown,
): <R extends Promise<IResultOfT<A, E>>>(r: R) => Promise<B>;
export function mapOrAsync<A, B, E>(
defaultValue: B,
fn: (a: A) => B | Promise<B>,
r: Promise<IResultOfT<A, E>>,
): Promise<B>;
export function mapOrAsync<A, B, E>(
defaultValue: B,
fn: (a: A) => B | Promise<B>,
r: Promise<IResultOfT<A, E>>,
onErr: (e: E) => unknown,
): Promise<B>;

Defined in: promise-result/mapOrAsync.ts

import { mapOrAsync, asyncOk, asyncErr } from '@sandlada/result/promise-result';
await mapOrAsync(-1, (x: number) => x * 2, asyncOk(5)); // 10
await mapOrAsync(-1, (x: number) => x * 2, asyncErr('boom')); // -1

Maps the success value of an async result, or computes a default from the error on failure. Both callbacks may be sync or async. Equivalent to mapAsync(fn).then(unwrapOrElseAsync(onErr)) but more efficient.

export function mapOrElseAsync<A, B, E>(
onErr: (e: E) => B | Promise<B>,
fn: (a: A) => B | Promise<B>,
): (r: Promise<IResultOfT<A, E>>) => Promise<B>;
export function mapOrElseAsync<A, B, E>(
onErr: (e: E) => B | Promise<B>,
fn: (a: A) => B | Promise<B>,
r: Promise<IResultOfT<A, E>>,
): Promise<B>;

Defined in: promise-result/mapOrElseAsync.ts

import { mapOrElseAsync, asyncOk, asyncErr } from '@sandlada/result/promise-result';
await mapOrElseAsync((e: string) => 0, (x: number) => x * 2, asyncOk(5)); // 10
await mapOrElseAsync((e: string) => -1, (x: number) => x * 2, asyncErr('boom')); // -1

Terminal — pattern-matches on both cases of an async result.

export function matchAsync<A, E, C>(
onOk: (a: A) => C | Promise<C>,
onErr: (e: E) => C | Promise<C>,
): (r: Promise<IResultOfT<A, E>>) => Promise<C>;
export function matchAsync<A, E, C>(
onOk: (a: A) => C | Promise<C>,
onErr: (e: E) => C | Promise<C>,
r: Promise<IResultOfT<A, E>>,
): Promise<C>;

Defined in: promise-result/matchAsync.ts

import { matchAsync, asyncOk } from '@sandlada/result/promise-result';
await matchAsync(
(v: number) => `success: ${v}`,
(e: string) => `failure: ${e}`,
asyncOk(42),
); // "success: 42"

Error recovery for async results. The success type widens to A | B.

Throw policy: a synchronous throw from f propagates via the outer promise rejection (the .then handler re-throws). A rejected Promise from f propagates as a rejection. Matches the canonical AsyncResult throw policy.

export function orElseAsync<E, B, F>(
f: (e: E) => IResultOfT<B, F> | Promise<IResultOfT<B, F>>,
): <A>(r: Promise<IResultOfT<A, E>>) => Promise<IResultOfT<A | B, F>>;
export function orElseAsync<A, E, B, F>(
f: (e: E) => IResultOfT<B, F> | Promise<IResultOfT<B, F>>,
r: Promise<IResultOfT<A, E>>,
): Promise<IResultOfT<A | B, F>>;

Defined in: promise-result/orElseAsync.ts

import { orElseAsync, asyncOk, asyncErr } from '@sandlada/result/promise-result';
await orElseAsync(
(e: string) => asyncOk('default'),
asyncErr('boom'),
);

Swaps the success and failure variants of a Promise<IResultOfT<A, E>>.

export function swapAsync<A, E>(
r: Promise<IResultOfT<A, E>>,
): Promise<IResultOfT<E, A>>;

Defined in: promise-result/swapAsync.ts

import { swapAsync } from '@sandlada/result/promise-result';
import { ok } from '@sandlada/result/factories';
const r = await swapAsync(Promise.resolve(ok(5))); // Err(5)

Side-effect on the success track of an async result.

export function tapAsync<A>(
fn: (a: A) => void | Promise<void>,
): <E>(r: Promise<IResultOfT<A, E>>) => Promise<IResultOfT<A, E>>;
export function tapAsync<A, E>(
fn: (a: A) => void | Promise<void>,
r: Promise<IResultOfT<A, E>>,
): Promise<IResultOfT<A, E>>;

Defined in: promise-result/tapAsync.ts

import { tapAsync, asyncOk } from '@sandlada/result/promise-result';
await tapAsync((v: string) => console.log('got:', v), asyncOk('hello'));

Side-effect on the failure track of an async result.

export function tapErrAsync<E>(
fn: (e: E) => void | Promise<void>,
): <A>(r: Promise<IResultOfT<A, E>>) => Promise<IResultOfT<A, E>>;
export function tapErrAsync<A, E>(
fn: (e: E) => void | Promise<void>,
r: Promise<IResultOfT<A, E>>,
): Promise<IResultOfT<A, E>>;

Defined in: promise-result/tapErrAsync.ts

import { tapErrAsync, asyncErr } from '@sandlada/result/promise-result';
await tapErrAsync((e: string) => console.log('err:', e), asyncErr('boom'));

Strictly synchronous unwrapOr over a Promise<IResultOfT> — extracts the success value or returns a default. The default may itself be a Promise.

Note: returns Promise<A>, NOT Promise<IResultOfT<A, _>>. The Async suffix on unwrapOrAsync is preserved for naming parity with mapAsync/mapErrAsync, but both unwrap the inner value.

export function unwrapOr<A>(
defaultValue: A | Promise<A>,
): <E>(r: Promise<IResultOfT<A, E>>) => Promise<A>;
export function unwrapOr<A, E>(
defaultValue: A | Promise<A>,
r: Promise<IResultOfT<A, E>>,
): Promise<A>;

Defined in: promise-result/unwrapOr.ts

import { unwrapOr, asyncOk, asyncErr } from '@sandlada/result/promise-result';
await unwrapOr(0, asyncOk(42)); // 42
await unwrapOr(0, asyncErr('x')); // 0

Extracts the success value from Promise<IResultOfT>, or returns a default on failure. The default value may itself be a Promise<A>; it is awaited internally.

Returns Promise<A> (just the inner value, not wrapped). The previous Promise<IResultOfT<A, unknown>> signature was a bug — unwrapOr semantically unwraps.

The default value type D is independent of the success type A, so a wider or sentinel value can be supplied as a fallback — e.g. unwrapOrAsync<null>(null) for a Promise<IResultOfT<User, NetworkError>> resolves to Promise<User | null>.

export function unwrapOrAsync<A, D = A>(
defaultValue: D | Promise<D>,
): <E>(r: Promise<IResultOfT<A, E>>) => Promise<A | D>;
export function unwrapOrAsync<A, E, D = A>(
defaultValue: D | Promise<D>,
r: Promise<IResultOfT<A, E>>,
): Promise<A | D>;

Defined in: promise-result/unwrapOrAsync.ts

import { unwrapOrAsync, asyncOk, asyncErr } from '@sandlada/result/promise-result';
await unwrapOrAsync(0, asyncOk(42)); // 42
await unwrapOrAsync(0, asyncErr('boom')); // 0
await unwrapOrAsync(Promise.resolve(0), asyncErr('boom')); // 0

Strictly lazy unwrapOrElse over a Promise<IResultOfT> — extracts the success value or computes a default from the error via a thunk. Returns Promise<A> (just the value).

export function unwrapOrElse<A, E>(
onErr: (e: E) => A | Promise<A>,
): (r: Promise<IResultOfT<A, E>>) => Promise<A>;
export function unwrapOrElse<A, E>(
onErr: (e: E) => A | Promise<A>,
r: Promise<IResultOfT<A, E>>,
): Promise<A>;

Defined in: promise-result/unwrapOrElse.ts

import { unwrapOrElse, asyncOk, asyncErr } from '@sandlada/result/promise-result';
await unwrapOrElse((e: string) => 0, asyncOk(42)); // 42
await unwrapOrElse((e: string) => 0, asyncErr('x')); // 0

Extracts the success value from Promise<IResultOfT>, or computes a default from the error on failure (lazy). The error handler may return a value or a Promise.

Returns Promise<A> (just the inner value).

The default value type D is independent of the success type A — the error handler may project to a different shape ((e) => null, (e) => defaultUser, etc.) and the result widens to A | D.

export function unwrapOrElseAsync<A, E, D = A>(
onErr: (e: E) => D | Promise<D>,
): (r: Promise<IResultOfT<A, E>>) => Promise<A | D>;
export function unwrapOrElseAsync<A, E, D>(
onErr: (e: E) => D | Promise<D>,
r: Promise<IResultOfT<A, E>>,
): Promise<A | D>;

Defined in: promise-result/unwrapOrElseAsync.ts

import { unwrapOrElseAsync, asyncOk, asyncErr } from '@sandlada/result/promise-result';
await unwrapOrElseAsync((e: string) => 0, asyncOk(42)); // 42
await unwrapOrElseAsync((e: string) => 0, asyncErr('x')); // 0

Re-exports asyncErr


Re-exports asyncOk