Lazy AsyncResult operators
AsyncResult — barrel export.
Re-exports all AsyncResult factories and operators.
Functions
Section titled “Functions”Returns res2 if res1 is Ok, otherwise returns the original Err.
Short-circuiting — res2 is not evaluated when res1 is Err.
export function and<T, U, E>( res1: AsyncResult<T, E>, res2: AsyncResult<U, E>,): AsyncResult<U, E>;Defined in: async-result/and.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { and, fromResult, match } from '@sandlada/result/async-result';
const first = fromResult(ok(1));const second = fromResult(ok(2));const combined = and(first, second);const value = await match({ ok: (n) => n, err: (e) => -1 }, combined);// value === 2
const short = and(fromResult(err('a')), second);const errValue = await match({ ok: (n) => `ok:${n}`, err: (e) => `err:${e}` }, short);// errValue === 'err:a'; and short-circuits without running secondandTee()
Section titled “andTee()”Side-effect on success (sync or async), ignoring the callback’s result.
Calls fn with the value on success and passes the original result through unchanged.
Lazy — returns a new AsyncResult without executing the inner computation.
Throw policy: If the side-effect callback throws (or rejects), the result
converts to err(caughtError) (canonical tap/tee policy — see AGENTS.md).
export function andTee<T, E>( fn: (value: T) => void | unknown | Promise<void | unknown>,): (ar: AsyncResult<T, E>) => AsyncResult<T, E>;export function andTee<T, E>( fn: (value: T) => void | unknown | Promise<void | unknown>, ar: AsyncResult<T, E>,): AsyncResult<T, E>;Defined in: async-result/andTee.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { andTee, fromResult, match } from '@sandlada/result/async-result';
const input = fromResult(ok(42));const teed = andTee((_v: number) => undefined, input);const label = await match({ ok: (n) => `ok:${n}`, err: (e) => `err:${String(e)}` }, teed);// label === 'ok:42'
const skipped = andTee((_v: number) => undefined, fromResult(err('skip')));const errLabel = await match({ ok: (n) => `ok:${n}`, err: (e) => `err:${e}` }, skipped);// errLabel === 'err:skip'; andTee short-circuits on ErrandThrough()
Section titled “andThrough()”Side-effect on success that can propagate errors. Calls fn with the value on success; if fn fails the failure widens into the original error type.
export function andThrough<T, E, F>( fn: (value: T) => AsyncResult<unknown, F> | Promise<IResultOfT<unknown, F>>,): (ar: AsyncResult<T, E>) => AsyncResult<T, E | F>;export function andThrough<T, E, F>( fn: (value: T) => AsyncResult<unknown, F> | Promise<IResultOfT<unknown, F>>, ar: AsyncResult<T, E>,): AsyncResult<T, E | F>;Defined in: async-result/andThrough.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { andThrough, fromResult, match } from '@sandlada/result/async-result';
const input = fromResult(ok(42));const validated = andThrough( (v: number) => (v > 0 ? fromResult(ok(undefined)) : fromResult(err('non-positive'))), input,);const label = await match({ ok: (n) => `ok:${n}`, err: (e) => `err:${e}` }, validated);// label === 'ok:42'
const bad = andThrough( (v: number) => (v > 0 ? fromResult(ok(undefined)) : fromResult(err('non-positive'))), fromResult(ok(-1)),);const errLabel = await match({ ok: (n) => `ok:${n}`, err: (e) => `err:${e}` }, bad);// errLabel === 'err:non-positive'; andThrough replaces Ok with the side-effect failureAsyncResult applicative ap — applies a function wrapped in an
AsyncResult to a value wrapped in an AsyncResult. If either is a failure, the
first failure propagates.
The function-result and value-result are allowed to have different error
types — the combined error widens to E | F. Matches the sync ap from
@sandlada/result/operators.
Mirrors the sync ap for AsyncResult pipelines, matching the fp-ts
Apply shape.
Execution: both carriers are started when .run() is called and run
concurrently - ap needs both sides, so it never short-circuits.
Throw policy: a throwing applied function is captured as Err(thrown).
export function ap<A, B, E, F>( fnResult: AsyncResult<(a: A) => B, E>,): (result: AsyncResult<A, F>) => AsyncResult<B, E | F>;export function ap<A, B, E, F>( fnResult: AsyncResult<(a: A) => B, E>, result: AsyncResult<A, F>,): AsyncResult<B, E | F>;Defined in: async-result/ap.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { ap, fromResult, match } from '@sandlada/result/async-result';
const fnCarrier = fromResult(ok((x: number) => x * 2));const valueCarrier = fromResult(ok(21));const applied = ap(fnCarrier, valueCarrier);const label = await match({ ok: (n) => `ok:${n}`, err: (e) => `err:${String(e)}` }, applied);// label === 'ok:42'
const brokenFn = fromResult(err('fn'));const stalled = ap(brokenFn, valueCarrier);const errLabel = await match({ ok: (n) => n, err: (e) => e }, stalled);// errLabel === 'fn'; ap propagates the function-side failurebimap()
Section titled “bimap()”Simultaneously maps both variants of an AsyncResult.
Throw policy: If onOk or onErr throws (or rejects), the result converts
to err(caughtError). Pass errorFn to customise how the thrown/rejected
value maps onto your error union.
export function bimap<T, E, U, F>( onOk: (value: T) => U | Promise<U>, onErr: (error: E) => F | Promise<F>, errorFn?: (thrown: unknown) => unknown,): (ar: AsyncResult<T, E>) => AsyncResult<U, F>;export function bimap<T, E, U, F>( onOk: (value: T) => U | Promise<U>, onErr: (error: E) => F | Promise<F>, ar: AsyncResult<T, E>, errorFn?: (thrown: unknown) => F,): AsyncResult<U, F>;Defined in: async-result/bimap.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { bimap, fromResult, match } from '@sandlada/result/async-result';
const input = fromResult(ok(5));const mapped = bimap( (v: number) => v.toString(), (e: string) => e.toUpperCase(), input,);const label = await match({ ok: (s) => s, err: (e) => e }, mapped);// label === '5'
const failed = bimap( (v: number) => v.toString(), (e: string) => e.toUpperCase(), fromResult(err('oops')),);const errLabel = await match({ ok: (s) => s, err: (e) => e }, failed);// errLabel === 'OOPS'bind()
Section titled “bind()”Chains an AsyncResult-returning function on success (monadic bind / flatMap).
Supports interoperability with standard Promise<IResultOfT>.
Lazy — returns a new AsyncResult without executing the inner computation.
The outer AsyncResult’s error type and the inner callback’s returned
AsyncResult error type are independent — the combined result widens to
E | F. Mirrors the sync operators/bind.ts so heterogeneous-error
pipelines (AppError/DbError) compose without manual unification.
Throw policy: If fn throws (sync) or rejects (async), the result
converts to err(caughtError). Pass errorFn to customise how the
thrown/rejected value maps onto your error union — e.g.
bind(fn, thrown => new MyError(String(thrown))).
export function bind<T, U, E, F>( fn: (value: T) => AsyncResult<U, F> | Promise<IResultOfT<U, F>>, errorFn?: (thrown: unknown) => unknown,): (ar: AsyncResult<T, E>) => AsyncResult<U, E | F>;export function bind<T, U, E, F>( fn: (value: T) => AsyncResult<U, F> | Promise<IResultOfT<U, F>>, ar: AsyncResult<T, E>, errorFn?: (thrown: unknown) => E | F,): AsyncResult<U, E | F>;Defined in: async-result/bind.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { bind, fromResult, match } from '@sandlada/result/async-result';
const input = fromResult(ok(1));const chained = bind((id: number) => fromResult(ok(id + 1)), input);const value = await match({ ok: (n) => n, err: () => -1 }, chained);// value === 2
const outerErr = fromResult(err('app'));const short = bind((id: number) => fromResult(ok(id + 1)), outerErr);const missed = await match({ ok: (n) => `ok:${n}`, err: (e) => `err:${e}` }, short);// missed === 'err:app'; bind short-circuits when the carrier is ErrcatchErr()
Section titled “catchErr()”Async variant of catchErr for AsyncResult.
Recovers from an error by returning a fallback value T (or a Promise resolving to T),
keeping the result track alive as a successful AsyncResult<T, never>.
Throw policy: failures inside onErr (sync throw or rejected Promise) are
captured into Err(thrown), mirroring orElse / filterOrElse. A rejection of
the source AsyncResult itself still propagates.
export function catchErr<A, E>( onErr: (e: E) => A | Promise<A>,): (ar: AsyncResult<A, E>) => AsyncResult<A, never>;export function catchErr<A, E>( onErr: (e: E) => A | Promise<A>, ar: AsyncResult<A, E>,): AsyncResult<A, never>;Defined in: async-result/catchErr.ts
Example
Section titled “Example”import { err, ok } from '@sandlada/result/factories';import { catchErr, fromResult, map, match } from '@sandlada/result/async-result';
const input = fromResult(err('boom'));const recovered = catchErr(() => 0, input);const label = await match({ ok: (n) => `ok:${n}`, err: () => 'err' }, recovered);// label === 'ok:0'
const healthy = catchErr(() => 0, fromResult(ok(21)));const doubled = map((x: number) => x * 2, healthy);const value = await match({ ok: (n) => n, err: () => -1 }, doubled);// value === 42; catchErr passes Ok through unchangedcombine()
Section titled “combine()”Combines an array of AsyncResults into a single AsyncResult of an array.
Short-circuits on the first failure (like Promise.all).
Lazy — returns a new AsyncResult without executing the inner computations.
export function combine<T, E>( results: readonly AsyncResult<T, E>[],): AsyncResult<T[], E>;Defined in: async-result/combine.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { combine, fromResult, match } from '@sandlada/result/async-result';
const parts = [fromResult(ok(1)), fromResult(ok(2))];const combined = combine(parts);const label = await match( { ok: (xs) => xs.join(','), err: (e) => `err:${String(e)}` }, combined,);// label === '1,2'
const broken = combine([fromResult(ok(1)), fromResult(err('stop'))]);const stopped = await broken.run();// stopped.isFailure; combine short-circuits on the first ErrcombineWithAllErrors()
Section titled “combineWithAllErrors()”Combines AsyncResults accumulating all errors (validation aggregation).
Unlike combine (short-circuit on first failure), this collects every error.
Lazy — returns a new AsyncResult without executing the inner computations.
export function combineWithAllErrors<T, E>( results: readonly AsyncResult<T, E>[],): AsyncResult<T[], E[]>;Defined in: async-result/combineWithAllErrors.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { combineWithAllErrors, fromResult, match } from '@sandlada/result/async-result';
const parts = [ fromResult(ok(1)), fromResult(err('a')), fromResult(err('b')),];const aggregated = combineWithAllErrors(parts);const label = await match( { ok: (xs) => xs.join(','), err: (es) => es.join('|') }, aggregated,);// label === 'a|b'
const allOk = combineWithAllErrors([fromResult(ok(1)), fromResult(ok(2))]);const okLabel = await match({ ok: (xs) => xs.length, err: () => 0 }, allOk);// okLabel === 2contains()
Section titled “contains()”Returns a Promise<boolean> indicating if the AsyncResult is success and contains the given value.
export function contains<T>( value: T,): <E>(ar: AsyncResult<T, E>) => Promise<boolean>;export function contains<T, E>( value: T, ar: AsyncResult<T, E>,): Promise<boolean>;Defined in: async-result/contains.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { contains, fromResult, map } from '@sandlada/result/async-result';
const input = map((x: number) => x, fromResult(ok(42)));const hit = await contains(42, input);const miss = await contains(0, input);// hit === true, miss === false
const failed = contains(42, fromResult(err('skip')));const onErr = await failed;// onErr === false; contains is false when the carrier is ErrcontainsErr()
Section titled “containsErr()”Returns true if the AsyncResult resolves to Err and contains the
given value. Strict equality (===).
export function containsErr<T, E>( error: E,): (ar: AsyncResult<T, E>) => Promise<boolean>;export function containsErr<T, E>( error: E, ar: AsyncResult<T, E>,): Promise<boolean>;Defined in: async-result/containsErr.ts
Example
Section titled “Example”import { err, ok } from '@sandlada/result/factories';import { containsErr, fromResult, mapErr } from '@sandlada/result/async-result';
const input = mapErr((e: string) => e, fromResult(err('boom')));const hit = await containsErr('boom', input);const miss = await containsErr('nope', input);// hit === true, miss === false
const onOk = await containsErr('boom', fromResult(ok(1)));// onOk === false; containsErr is false on Ok carriersexists()
Section titled “exists()”Returns a Promise<boolean> indicating if the AsyncResult is success and the predicate holds.
export function exists<T>( predicate: (value: T) => boolean | Promise<boolean>,): <E>(ar: AsyncResult<T, E>) => Promise<boolean>;export function exists<T, E>( predicate: (value: T) => boolean | Promise<boolean>, ar: AsyncResult<T, E>,): Promise<boolean>;Defined in: async-result/exists.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { exists, fromResult, map } from '@sandlada/result/async-result';
const input = map((x: number) => x, fromResult(ok(42)));const yes = await exists((v: number) => v > 0, input);const no = await exists((v: number) => v < 0, input);// yes === true, no === false
const onErr = await exists((v: number) => v > 0, fromResult(err('skip')));// onErr === false; exists is false when the carrier is Errexpect()
Section titled “expect()”Like unwrap but throws an Error carrying the supplied message.
Useful for marking program-contract violations with a domain-specific
message.
The original error value is preserved as Error.cause (and via the
optional formatErr hook for custom string shaping), so structured
E shapes don’t get clobbered to [object Object].
Pass formatErr to customise how the original error value is rendered
in the message; pass throwingFn to fully replace the thrown Error
class — e.g. expect(msg, ar, info => new MyError(info.message, info.value)).
export function expect<T, E>( message: string, ar: AsyncResult<T, E>, formatErr?: (error: E) => string,): Promise<T>;export function expect<T, E>( message: string, ar: AsyncResult<T, E>, formatErr: ((error: E) => string) | undefined, throwingFn: (info: { message: string; value: E }) => Error,): Promise<T>;Defined in: async-result/expect.ts
Example
Section titled “Example”import { err, ok } from '@sandlada/result/factories';import { expect, fromResult, map } from '@sandlada/result/async-result';
const input = map((x: number) => x, fromResult(ok(42)));const value = await expect('must succeed', input);// value === 42
const doomed = expect('config must be valid', fromResult(err('boom')));// await doomed throws Error with cause 'boom'expectErr()
Section titled “expectErr()”Like unwrapErr but throws an Error carrying the supplied message.
Useful when reaching a success path is itself a contract violation.
The original success value is preserved as Error.cause (and via the
optional throwingFn hook for full customisation), so structured T
shapes don’t get lost.
export function expectErr<T, E>( message: string, ar: AsyncResult<T, E>, throwingFn?: (info: { message: string; value: T }) => Error,): Promise<E>;Defined in: async-result/expectErr.ts
Example
Section titled “Example”import { err, ok } from '@sandlada/result/factories';import { expectErr, fromResult, mapErr } from '@sandlada/result/async-result';
const input = mapErr((e: string) => e, fromResult(err('boom')));const error = await expectErr('must fail', input);// error === 'boom'
const doomed = expectErr('should have failed', fromResult(ok(42)));// await doomed throws Error with cause 42filterOrElse()
Section titled “filterOrElse()”Filters the success value of an AsyncResult with a predicate.
If the predicate holds, the original success passes through. If it fails,
returns err(errorFn(value)). Failures pass through unchanged.
Lazy — returns a new AsyncResult without executing the inner computation.
Throw policy: If the predicate or errorFn throws synchronously or
returns a rejected Promise, the error is caught and the result converts to
err(caughtError) (canonical catch+convert policy — see AGENTS.md).
export function filterOrElse<T, E>( predicate: (value: T) => boolean | Promise<boolean>, errorFn: (value: T) => E | Promise<E>,): (ar: AsyncResult<T, E>) => AsyncResult<T, E>;export function filterOrElse<T, E>( predicate: (value: T) => boolean | Promise<boolean>, errorFn: (value: T) => E | Promise<E>, ar: AsyncResult<T, E>,): AsyncResult<T, E>;Defined in: async-result/filterOrElse.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { filterOrElse, fromResult, match } from '@sandlada/result/async-result';
const input = fromResult(ok(42));const kept = filterOrElse((x: number) => x > 0, (x: number) => `neg:${x}`, input);const label = await match({ ok: (n) => `ok:${n}`, err: (e) => e }, kept);// label === 'ok:42'
const rejected = filterOrElse( (x: number) => x > 0, (x: number) => `neg:${x}`, fromResult(ok(-1)),);const errLabel = await match({ ok: (n) => `ok:${n}`, err: (e) => e }, rejected);// errLabel === 'neg:-1'flatten()
Section titled “flatten()”Flattens a nested AsyncResult.
Single-step only: unwraps exactly one layer. Call flatten repeatedly
to flatten deeper nests.
export function flatten<T, E>( ar: AsyncResult<AsyncResult<T, E>, E>,): AsyncResult<T, E>;Defined in: async-result/flatten.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { flatten, fromResult, map, unwrap } from '@sandlada/result/async-result';
const nested = fromResult(ok(fromResult(ok(42))));const flat = flatten(nested);const doubled = map((x: number) => x * 2, flat);const value = await unwrap(doubled);// value === 84
const broken = flatten(fromResult(err('outer')));const stopped = await broken.run();// stopped stays Err('outer'); flatten short-circuits on outer failurefrom()
Section titled “from()”Creates an AsyncResult from a thunk that returns a Result or a
Promise<Result>. The thunk is lazy - it won’t execute until .run() is
called.
The carrier’s run() always returns a Promise: a thunk that returns a plain
Result is awaited, and a thunk that throws synchronously surfaces as a
rejected promise instead of escaping as a raw exception.
export function from<T, E = unknown>( thunk: () => IResultOfT<T, E> | Promise<IResultOfT<T, E>>,): AsyncResult<T, E>;Defined in: async-result/from.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { from, map, match } from '@sandlada/result/async-result';
const input = from(() => Promise.resolve(ok(21)));const doubled = map((x: number) => x * 2, input);const label = await match( { ok: (n) => `ok:${n}`, err: (e) => `err:${String(e)}` }, doubled,);// label === 'ok:42'
const lazyErr = from(() => err('skip'));const skipped = await map((x: number) => x * 2, lazyErr).run();// skipped stays Err('skip'); map does not run the success mapperfromPromise()
Section titled “fromPromise()”Wraps a Promise<T> into an AsyncResult, catching rejections.
The inner Promise is not yet created at construction time; the factory thunk is invoked
lazily when .run() is called.
export function fromPromise<T, E = unknown>( thunk: () => Promise<T>, errorFn?: (error: unknown) => E,): AsyncResult<T, E>;Defined in: async-result/fromPromise.ts
Example
Section titled “Example”import { fromPromise, map, match } from '@sandlada/result/async-result';
const input = fromPromise(() => Promise.resolve(21));const doubled = map((x: number) => x * 2, input);const label = await match( { ok: (n) => `ok:${n}`, err: (e) => `err:${String(e)}` }, doubled,);// label === 'ok:42'
const rejected = fromPromise(() => Promise.reject('net'));const fallback = await match( { ok: (n) => n, err: (e) => -1 }, map((x: number) => x, rejected),);// fallback === -1; fromPromise turns rejection into Err before map runsfromResult()
Section titled “fromResult()”Wraps a sync IResultOfT into an AsyncResult (lifts a sync Result into the async world).
For transforming the success value with an async callback on a sync Result, see
bridge-result map instead.
export function fromResult<T, E = unknown>( result: IResultOfT<T, E>,): AsyncResult<T, E>;Defined in: async-result/fromResult.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { fromResult, map, match } from '@sandlada/result/async-result';
const syncOk = ok(21);const input = fromResult(syncOk);const doubled = map((x: number) => x * 2, input);const label = await match( { ok: (n) => `ok:${n}`, err: (e) => `err:${String(e)}` }, doubled,);// label === 'ok:42'
const failed = fromResult(err('skip'));const passthrough = await map((x: number) => x * 2, failed).run();// passthrough stays Err('skip'); map short-circuits on failureisErr()
Section titled “isErr()”Returns true if the AsyncResult resolves to Err. Mirrors the
IResultOfT.isFailure discriminator as a standalone function.
export function isErr<T, E>(ar: AsyncResult<T, E>): Promise<boolean>;Defined in: async-result/isErr.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { fromResult, isErr, mapErr } from '@sandlada/result/async-result';
const input = mapErr((e: string) => e, fromResult(err('x')));const yes = await isErr(input);const no = await isErr(fromResult(ok(42)));// yes === true, no === falseisOk()
Section titled “isOk()”Returns true if the AsyncResult resolves to Ok. Mirrors the
IResultOfT.isSuccess discriminator as a standalone function.
export function isOk<T, E>(ar: AsyncResult<T, E>): Promise<boolean>;Defined in: async-result/isOk.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { fromResult, isOk, map } from '@sandlada/result/async-result';
const input = map((x: number) => x + 1, fromResult(ok(41)));const yes = await isOk(input);const no = await isOk(fromResult(err('x')));// yes === true, no === falseMaps the success value of an AsyncResult using a synchronous function. Lazy — returns a new AsyncResult without executing the inner computation.
Throw policy: If fn throws, the result converts to err(caughtError).
Pass errorFn to customise how the thrown value maps onto your error union.
export function map<T, U, E>( fn: (value: T) => U, errorFn?: (thrown: unknown) => unknown,): (ar: AsyncResult<T, E>) => AsyncResult<U, E>;export function map<T, U, E>( fn: (value: T) => U, ar: AsyncResult<T, E>, errorFn?: (thrown: unknown) => E,): AsyncResult<U, E>;Defined in: async-result/map.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { fromResult, map, match } from '@sandlada/result/async-result';
const input = fromResult(ok(21));const doubled = map((x: number) => x * 2, input);const label = await match( { ok: (n) => `ok:${n}`, err: (e) => `err:${String(e)}` }, doubled,);// label === 'ok:42'
const skipped = fromResult(err('skip'));const passthrough = await map((x: number) => x * 2, skipped).run();// passthrough stays Err('skip'); map short-circuits on failuremapAsync()
Section titled “mapAsync()”Maps the success value of an AsyncResult. The callback may be
sync or async (U | Promise<U>); sync results are awaited internally.
Lazy — returns a new AsyncResult without executing the inner computation.
Throw policy: a synchronous throw from fn propagates as a rejection of
.run(); a rejected Promise from fn likewise propagates. The optional
errorFn only remaps the rejection payload — it does NOT convert the
rejection into an Err. The thrown value passed to errorFn is whatever
.run() would otherwise reject with; the returned value replaces that
rejection reason. This matches the canonical AsyncResult “propagates”
policy. For catch-and-convert behaviour (where the rejection becomes
Err(mapped)), use map (which has different throw semantics) or wrap
the operation in a try/catch.
export function mapAsync<T, U, E>( fn: (value: T) => U | Promise<U>, errorFn?: (thrown: unknown) => unknown,): (ar: AsyncResult<T, E>) => AsyncResult<U, E>;export function mapAsync<T, U, E>( fn: (value: T) => U | Promise<U>, ar: AsyncResult<T, E>, errorFn?: (thrown: unknown) => E,): AsyncResult<U, E>;Defined in: async-result/mapAsync.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { fromResult, mapAsync, match } from '@sandlada/result/async-result';
const input = fromResult(ok(21));const doubled = mapAsync(async (x: number) => x * 2, input);const label = await match( { ok: (n) => `ok:${n}`, err: (e) => `err:${String(e)}` }, doubled,);// label === 'ok:42'
const skipped = fromResult(err('skip'));const passthrough = await mapAsync((x: number) => x * 2, skipped).run();// passthrough stays Err('skip'); mapAsync short-circuits on failuremapErr()
Section titled “mapErr()”Maps the error of an AsyncResult using a synchronous function. Lazy — returns a new AsyncResult without executing the inner computation.
Throw policy: If fn throws, the result converts to err(caughtError).
Pass errorFn to customise how the thrown value maps onto your error union.
export function mapErr<T, E, F>( fn: (error: E) => F, errorFn?: (thrown: unknown) => unknown,): (ar: AsyncResult<T, E>) => AsyncResult<T, F>;export function mapErr<T, E, F>( fn: (error: E) => F, ar: AsyncResult<T, E>, errorFn?: (thrown: unknown) => F,): AsyncResult<T, F>;Defined in: async-result/mapErr.ts
Example
Section titled “Example”import { err, ok } from '@sandlada/result/factories';import { fromResult, mapErr, match } from '@sandlada/result/async-result';
const input = fromResult(err('oops'));const mapped = mapErr((e: string) => e.toUpperCase(), input);const errLabel = await match({ ok: () => 'ok', err: (e) => e }, mapped);// errLabel === 'OOPS'
const healthy = mapErr((e: string) => e.toUpperCase(), fromResult(ok(21)));const passthrough = await match({ ok: (n) => n, err: () => -1 }, healthy);// passthrough === 21; mapErr leaves Ok values unchangedmapErrAsync()
Section titled “mapErrAsync()”Maps the error of an AsyncResult using an async function. Lazy — returns a new AsyncResult without executing the inner computation.
export function mapErrAsync<T, E, F>( fn: (error: E) => F | Promise<F>,): (ar: AsyncResult<T, E>) => AsyncResult<T, F>;export function mapErrAsync<T, E, F>( fn: (error: E) => F | Promise<F>, ar: AsyncResult<T, E>,): AsyncResult<T, F>;Defined in: async-result/mapErrAsync.ts
Example
Section titled “Example”import { err, ok } from '@sandlada/result/factories';import { fromResult, mapErrAsync, match } from '@sandlada/result/async-result';
const input = fromResult(err('oops'));const mapped = mapErrAsync(async (e: string) => e.toUpperCase(), input);const errLabel = await match({ ok: () => 'ok', err: (e) => e }, mapped);// errLabel === 'OOPS'
const healthy = mapErrAsync(async (e: string) => e.toUpperCase(), fromResult(ok(7)));const passthrough = await match({ ok: (n) => n, err: () => -1 }, healthy);// passthrough === 7; mapErrAsync skips the mapper on OkmapOr()
Section titled “mapOr()”Maps the success value of an AsyncResult, or returns a default on failure.
The mapper may be sync or async. Sync throws from the mapper are caught
and converted to the default (canonical AsyncResult catch+convert policy).
export function mapOr<T, U, E>( defaultValue: U, fn: (value: T) => U | Promise<U>,): (ar: AsyncResult<T, E>) => Promise<U>;export function mapOr<T, U, E>( defaultValue: U, fn: (value: T) => U | Promise<U>, ar: AsyncResult<T, E>,): Promise<U>;Defined in: async-result/mapOr.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { fromResult, mapOr, map } from '@sandlada/result/async-result';
const input = map((x: number) => x, fromResult(ok(21)));const mapped = await mapOr(-1, (x: number) => x * 2, input);// mapped === 42
const fallback = await mapOr(-1, (x: number) => x * 2, fromResult(err('x')));// fallback === -1; mapOr skips the mapper on ErrmapOrElse()
Section titled “mapOrElse()”Maps the success value of an AsyncResult, or computes a default from the
error on failure. Both callbacks may be sync or async. Lazy — onErr is
only called on failure.
export function mapOrElse<T, U, E>( onErr: (error: E) => U | Promise<U>, fn: (value: T) => U | Promise<U>,): (ar: AsyncResult<T, E>) => Promise<U>;export function mapOrElse<T, U, E>( onErr: (error: E) => U | Promise<U>, fn: (value: T) => U | Promise<U>, ar: AsyncResult<T, E>,): Promise<U>;Defined in: async-result/mapOrElse.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { fromResult, mapOrElse, map } from '@sandlada/result/async-result';
const input = map((x: number) => x, fromResult(ok(21)));const mapped = await mapOrElse((e: string) => -1, (x: number) => x * 2, input);// mapped === 42
const fromErr = await mapOrElse((e: string) => -1, (x: number) => x * 2, fromResult(err('x')));// fromErr === -1; mapOrElse uses onErr when the carrier is Errmatch()
Section titled “match()”Terminal operator — executes the AsyncResult and applies either the success
handler or the error handler. Returns a Promise<U>.
export function match<T, E, U>( handlers: { ok: (value: T) => U | Promise<U>; err: (error: E) => U | Promise<U> },): (ar: AsyncResult<T, E>) => Promise<U>;export function match<T, E, U>( handlers: { ok: (value: T) => U | Promise<U>; err: (error: E) => U | Promise<U> }, ar: AsyncResult<T, E>,): Promise<U>;Defined in: async-result/match.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { fromResult, map, match } from '@sandlada/result/async-result';
const input = fromResult(ok(21));const pipeline = map((x: number) => x * 2, input);const label = await match( { ok: (n) => `ok:${n}`, err: (e) => `err:${String(e)}` }, pipeline,);// label === 'ok:42'
const failed = map((x: number) => x * 2, fromResult(err('skip')));const errLabel = await match( { ok: (n) => `ok:${n}`, err: (e) => `err:${String(e)}` }, failed,);// errLabel === 'err:skip'Returns res1 if it is Ok, otherwise returns res2. Short-circuiting —
res2 is not evaluated when res1 is Ok.
export function or<T, E, F>( res1: AsyncResult<T, E>, res2: AsyncResult<T, F>,): AsyncResult<T, E | F>;Defined in: async-result/or.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { fromResult, match, or } from '@sandlada/result/async-result';
const primary = fromResult(ok(1));const backup = fromResult(ok(2));const picked = or(primary, backup);const value = await match({ ok: (n) => n, err: () => -1 }, picked);// value === 1
const failed = or(fromResult(err('a')), backup);const recovered = await match({ ok: (n) => `ok:${n}`, err: (e) => `err:${e}` }, failed);// recovered === 'ok:2'; or runs backup when primary is ErrorElse()
Section titled “orElse()”Recovers from failure by chaining to an alternative AsyncResult or Promise<IResult>. Lazy — returns a new AsyncResult without executing the inner computation.
Throw policy: If fn throws (sync) or rejects (async), the result converts
to err(caughtError). Pass errorFn to customise how the thrown value maps
onto your error union.
export function orElse<T, E, F>( fn: (error: E) => AsyncResult<T, F> | Promise<IResultOfT<T, F>>, errorFn?: (thrown: unknown) => unknown,): (ar: AsyncResult<T, E>) => AsyncResult<T, E | F>;export function orElse<T, E, F>( fn: (error: E) => AsyncResult<T, F> | Promise<IResultOfT<T, F>>, ar: AsyncResult<T, E>, errorFn?: (thrown: unknown) => E | F,): AsyncResult<T, E | F>;Defined in: async-result/orElse.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { fromResult, map, orElse, match } from '@sandlada/result/async-result';
const input = fromResult(err('fail'));const recovered = orElse(() => fromResult(ok(0)), input);const value = await match({ ok: (n) => n, err: () => -1 }, recovered);// value === 0
const healthy = orElse(() => fromResult(ok(0)), fromResult(ok(21)));const doubled = map((x: number) => x * 2, healthy);const label = await match({ ok: (n) => n, err: () => -1 }, doubled);// label === 42; orElse leaves Ok carriers untouchedorTee()
Section titled “orTee()”Side-effect on failure (sync or async), ignoring the callback’s result.
Calls fn with the error on failure and passes the original result through unchanged.
Lazy — returns a new AsyncResult without executing the inner computation.
Throw policy: If the side-effect callback throws (or rejects), the result
converts to err(caughtError) (canonical tap/tee policy — see AGENTS.md).
export function orTee<T, E>( fn: (error: E) => void | unknown | Promise<void | unknown>,): (ar: AsyncResult<T, E>) => AsyncResult<T, E>;export function orTee<T, E>( fn: (error: E) => void | unknown | Promise<void | unknown>, ar: AsyncResult<T, E>,): AsyncResult<T, E>;Defined in: async-result/orTee.ts
Example
Section titled “Example”import { err, ok } from '@sandlada/result/factories';import { fromResult, orTee, match } from '@sandlada/result/async-result';
const input = fromResult(err('oops'));const teed = orTee((_e: string) => undefined, input);const errLabel = await match({ ok: () => 'ok', err: (e) => e }, teed);// errLabel === 'oops'
const healthy = orTee((_e: string) => undefined, fromResult(ok(21)));const label = await match({ ok: (n) => n, err: () => -1 }, healthy);// label === 21; orTee does not run the side effect on OkswapAsync()
Section titled “swapAsync()”AsyncResult analogue of swap. Swaps the Ok and Err
variants of an AsyncResult. Renamed from swap to align with mapAsync and
other async-result operators.
export function swapAsync<T, E>( ar: AsyncResult<T, E>,): AsyncResult<E, T>;Defined in: async-result/swapAsync.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { fromResult, swapAsync, match } from '@sandlada/result/async-result';
const input = fromResult(ok(5));const flipped = swapAsync(input);const errSide = await match({ ok: () => 'ok', err: (e) => `err:${e}` }, flipped);// errSide === 'err:5'
const fromErr = swapAsync(fromResult(err('x')));const okSide = await match({ ok: (n) => n, err: () => 'fail' }, fromErr);// okSide === 'x'; swapAsync moves failure payload to OkSide-effect on the success track. Calls fn with the value on success
and passes the original result through unchanged.
Lazy — returns a new AsyncResult without executing the inner computation.
The callback may be sync or async — fn is awaited internally so async
rejections surface before the original result is returned.
Throw policy: If fn throws or rejects, the result converts to
err(caughtError). Pass errorFn to customise how the thrown value maps
onto your error union — e.g. tap(fn, thrown => new MyError(String(thrown))).
export function tap<T, E>( fn: (value: T) => void | Promise<void>, errorFn?: (thrown: unknown) => unknown,): (ar: AsyncResult<T, E>) => AsyncResult<T, E>;export function tap<T, E>( fn: (value: T) => void | Promise<void>, ar: AsyncResult<T, E>, errorFn?: (thrown: unknown) => E,): AsyncResult<T, E>;Defined in: async-result/tap.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { fromResult, tap, match } from '@sandlada/result/async-result';
const input = fromResult(ok(42));const tapped = tap((_v: number) => undefined, input);const label = await match({ ok: (n) => `ok:${n}`, err: (e) => `err:${String(e)}` }, tapped);// label === 'ok:42'
const skipped = tap((_v: number) => undefined, fromResult(err('skip')));const errLabel = await match({ ok: (n) => `ok:${n}`, err: (e) => `err:${e}` }, skipped);// errLabel === 'err:skip'; tap short-circuits on Err without running the side effecttapAsync()
Section titled “tapAsync()”Side-effect on the success track using an async function. Lazy — returns a new AsyncResult without executing the inner computation.
export function tapAsync<T, E>( fn: (value: T) => void | Promise<void>,): (ar: AsyncResult<T, E>) => AsyncResult<T, E>;export function tapAsync<T, E>( fn: (value: T) => void | Promise<void>, ar: AsyncResult<T, E>,): AsyncResult<T, E>;Defined in: async-result/tapAsync.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { fromResult, tapAsync, match } from '@sandlada/result/async-result';
const input = fromResult(ok(42));const tapped = tapAsync(async (_v: number) => undefined, input);const label = await match({ ok: (n) => `ok:${n}`, err: (e) => `err:${String(e)}` }, tapped);// label === 'ok:42'
const skipped = tapAsync(async (_v: number) => undefined, fromResult(err('skip')));const errLabel = await match({ ok: (n) => `ok:${n}`, err: (e) => `err:${e}` }, skipped);// errLabel === 'err:skip'; tapAsync does not invoke the callback on ErrtapErr()
Section titled “tapErr()”Side-effect on the error track. Calls fn with the error on failure
and passes the original result through unchanged.
Lazy — returns a new AsyncResult without executing the inner computation.
The callback may be sync or async — fn is awaited internally so async
rejections surface before the original result is returned.
Throw policy: If fn throws or rejects, the result converts to
err(caughtError). Pass errorFn to customise how the thrown value maps
onto your error union.
export function tapErr<T, E>( fn: (error: E) => void | Promise<void>, errorFn?: (thrown: unknown) => unknown,): (ar: AsyncResult<T, E>) => AsyncResult<T, E>;export function tapErr<T, E>( fn: (error: E) => void | Promise<void>, ar: AsyncResult<T, E>, errorFn?: (thrown: unknown) => E,): AsyncResult<T, E>;Defined in: async-result/tapErr.ts
Example
Section titled “Example”import { err, ok } from '@sandlada/result/factories';import { fromResult, tapErr, match } from '@sandlada/result/async-result';
const input = fromResult(err('oops'));const tapped = tapErr((_e: string) => undefined, input);const errLabel = await match({ ok: () => 'ok', err: (e) => e }, tapped);// errLabel === 'oops'
const healthy = tapErr((_e: string) => undefined, fromResult(ok(21)));const label = await match({ ok: (n) => n, err: () => -1 }, healthy);// label === 21; tapErr skips the callback on OktapErrAsync()
Section titled “tapErrAsync()”Side-effect on the error track using an async function. Lazy — returns a new AsyncResult without executing the inner computation.
export function tapErrAsync<T, E>( fn: (error: E) => void | Promise<void>,): (ar: AsyncResult<T, E>) => AsyncResult<T, E>;export function tapErrAsync<T, E>( fn: (error: E) => void | Promise<void>, ar: AsyncResult<T, E>,): AsyncResult<T, E>;Defined in: async-result/tapErrAsync.ts
Example
Section titled “Example”import { err, ok } from '@sandlada/result/factories';import { fromResult, tapErrAsync, match } from '@sandlada/result/async-result';
const input = fromResult(err('oops'));const tapped = tapErrAsync(async (_e: string) => undefined, input);const errLabel = await match({ ok: () => 'ok', err: (e) => e }, tapped);// errLabel === 'oops'
const healthy = tapErrAsync(async (_e: string) => undefined, fromResult(ok(9)));const label = await match({ ok: (n) => n, err: () => -1 }, healthy);// label === 9; tapErrAsync passes Ok through without calling the handlerunwrap()
Section titled “unwrap()”Extracts the success value from an AsyncResult, or throws on failure.
Use sparingly — prefer unwrapOr, unwrapOrElse, or match in most code.
The original error value is preserved as Error.cause (or via the
optional formatErr hook), so structured E shapes don’t get
clobbered to [object Object]. Pass throwingFn to fully replace the
thrown Error class.
export function unwrap<T, E>(ar: AsyncResult<T, E>): Promise<T>;export function unwrap<T, E>( ar: AsyncResult<T, E>, formatErr?: (error: E) => string,): Promise<T>;export function unwrap<T, E>( ar: AsyncResult<T, E>, formatErr: ((error: E) => string) | undefined, throwingFn: (info: { message: string; value: E }) => Error,): Promise<T>;Defined in: async-result/unwrap.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { fromResult, map, unwrap } from '@sandlada/result/async-result';
const input = map((x: number) => x * 2, fromResult(ok(21)));const value = await unwrap(input);// value === 42
const doomed = unwrap(fromResult(err('boom')));// await doomed throws Error with cause 'boom'unwrapErr()
Section titled “unwrapErr()”Extracts the error from a failed AsyncResult, or throws on success.
The dual of unwrap.
The original success value is preserved as Error.cause, so structured
T shapes don’t get lost. Pass throwingFn to fully replace the
thrown Error class.
export function unwrapErr<T, E>(ar: AsyncResult<T, E>): Promise<E>;export function unwrapErr<T, E>( ar: AsyncResult<T, E>, throwingFn?: (info: { message: string; value: T }) => Error,): Promise<E>;Defined in: async-result/unwrapErr.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { fromResult, mapErr, unwrapErr } from '@sandlada/result/async-result';
const input = mapErr((e: string) => e, fromResult(err('boom')));const error = await unwrapErr(input);// error === 'boom'
const doomed = unwrapErr(fromResult(ok(42)));// await doomed throws Error with cause 42unwrapOr()
Section titled “unwrapOr()”Terminal operator — executes the AsyncResult and returns the success value, or a default value on failure. The default value may be sync or a Promise.
export function unwrapOr<T, E>( defaultValue: T | Promise<T>,): (ar: AsyncResult<T, E>) => Promise<T>;export function unwrapOr<T, E>( defaultValue: T | Promise<T>, ar: AsyncResult<T, E>,): Promise<T>;Defined in: async-result/unwrapOr.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { fromResult, map, unwrapOr } from '@sandlada/result/async-result';
const input = map((x: number) => x, fromResult(ok(42)));const value = await unwrapOr(0, input);// value === 42
const fallback = await unwrapOr(0, fromResult(err('fail')));// fallback === 0; unwrapOr returns the default on ErrunwrapOrElse()
Section titled “unwrapOrElse()”Extracts the success value from an AsyncResult, or computes a default from
the error on failure. The handler may be sync or async. Lazy — the handler
is only called on failure.
export function unwrapOrElse<T = unknown, E = unknown, U = unknown>( onErr: (error: E) => U | Promise<U>,): <T2 extends T>(ar: AsyncResult<T2, E>) => Promise<T2 | U>;export function unwrapOrElse<T, E, U>( onErr: (error: E) => U | Promise<U>, ar: AsyncResult<T, E>,): Promise<T | U>;Defined in: async-result/unwrapOrElse.ts
Example
Section titled “Example”import { ok, err } from '@sandlada/result/factories';import { fromResult, map, unwrapOrElse } from '@sandlada/result/async-result';
const input = map((x: number) => x, fromResult(ok(42)));const value = await unwrapOrElse(() => 0, input);// value === 42
const computed = await unwrapOrElse((e: string) => -1, fromResult(err('boom')));// computed === -1; unwrapOrElse calls the handler only on Err