Skip to content

Promise Option operators

Async operators on Promise<IOption<T>> — barrel export.

Mirrors the structure of promise-result/ but for the Option type. Callbacks may be sync or async; predicates use catch+convert policy.

Chains an async option-returning function over a sync IOption. Bridges from the sync Option world to the async world — unlike bind in async-option/ which works on AsyncOption.

Throw policy: a synchronous throw from fn converts to None; a rejected Promise from fn propagates as an outer rejection (promotion-family rule — the sync track stays rejection-free, and async failures are not swallowed).

export function asyncBindOption<T, U>(
fn: (value: T) => Promise<IOption<U>>,
): (opt: IOption<T>) => Promise<IOption<U>>;
export function asyncBindOption<T, U>(
fn: (value: T) => Promise<IOption<U>>,
opt: IOption<T>,
): Promise<IOption<U>>;

Defined in: promise-option/asyncBindOption.ts

import { asyncBindOption, ofSome } from '@sandlada/result/promise-option';
const r = await asyncBindOption(async (x: number) => ofSome(x * 2), ofSome(21));
// Some(42)

Lifts a sync IOption<T> into Promise<IOption<U>> via an async mapper. Companion to asyncMap for the Option world.

export function asyncMapOption<A, B>(
f: (a: A) => Promise<B>,
): (o: IOption<A>) => Promise<IOption<B>>;
export function asyncMapOption<A, B>(
f: (a: A) => Promise<B>,
o: IOption<A>,
): Promise<IOption<B>>;

Defined in: promise-option/asyncMapOption.ts

import { asyncMapOption, ofSome, ofNone } from '@sandlada/result/promise-option';
await asyncMapOption(async (x: number) => x * 2, ofSome(21)); // Some(42)
await asyncMapOption(async (x: number) => x * 2, ofNone()); // None

Async match for sync IOption<T>. Pattern-matches with async-allowed handlers.

export function asyncMatchOption<T, U>(
handlers: { some: (value: T) => U | Promise<U>; none: () => U | Promise<U> },
): (o: IOption<T>) => Promise<U>;
export function asyncMatchOption<T, U>(
handlers: { some: (value: T) => U | Promise<U>; none: () => U | Promise<U> },
o: IOption<T>,
): Promise<U>;

Defined in: promise-option/asyncMatchOption.ts

import { asyncMatchOption, ofSome, ofNone } from '@sandlada/result/promise-option';
await asyncMatchOption(
{ some: async (v: number) => `got ${v}`, none: async () => 'absent' },
ofSome(42),
); // 'got 42'

Lifts a sync IOption<T> into Promise<IOption<T>> and recovers from None via an async callback.

Throw policy: a synchronous throw from f converts to None; a rejected Promise from f propagates as an outer rejection (promotion-family rule).

export function asyncOrElseOption<T>(
f: () => Promise<IOption<T>>,
): (o: IOption<T>) => Promise<IOption<T>>;
export function asyncOrElseOption<T>(
f: () => Promise<IOption<T>>,
o: IOption<T>,
): Promise<IOption<T>>;

Defined in: promise-option/asyncOrElseOption.ts

import { asyncOrElseOption, ofSome, ofNone } from '@sandlada/result/promise-option';
await asyncOrElseOption(async () => ofSome(0), ofNone()); // Some(0)
await asyncOrElseOption(async () => ofSome(0), ofSome(42)); // Some(42)

Side-effect on success for a sync IOption using an async callback.

Side-effect only. A synchronous throw from the callback converts to None (side-effect dropped); a rejected Promise propagates as an outer rejection (promotion-family rule, matches asyncBindOption).

export function asyncTapOption<T>(
fn: (a: T) => Promise<void | unknown>,
): (opt: IOption<T>) => Promise<IOption<T>>;
export function asyncTapOption<T>(
fn: (a: T) => Promise<void | unknown>,
opt: IOption<T>,
): Promise<IOption<T>>;

Defined in: promise-option/asyncTapOption.ts

import { ofSome, asyncTapOption } from '@sandlada/result/promise-option';
const log = asyncTapOption(async (x: number) => { console.log(x); });
await log(ofSome(42)); // Some(42) — side-effect only

Chains an async option-returning function. fn can return IOption or Promise<IOption>.

Throw policy: if fn throws synchronously or its returned Promise rejects, the result is None. The thrown reason is discarded.

export function bindAsyncOption<T, U>(
f: (a: T) => IOption<U> | Promise<IOption<U>>,
): (r: Promise<IOption<T>>) => Promise<IOption<U>>;
export function bindAsyncOption<T, U>(
f: (a: T) => IOption<U> | Promise<IOption<U>>,
r: Promise<IOption<T>>,
): Promise<IOption<U>>;

Defined in: promise-option/bindAsyncOption.ts

import { bindAsyncOption } from '@sandlada/result/promise-option';
import { ofSome, ofNone } from '@sandlada/result/promise-option';
await bindAsyncOption(
(x: number) => x > 0 ? Promise.resolve(ofSome(x * 2)) : Promise.resolve(ofNone()),
Promise.resolve(ofSome(21)),
);

Returns true if the Promise<IOption> is Some and contains the given value.

export function containsAsyncOption<T>(
value: T,
): (r: Promise<IOption<T>>) => Promise<boolean>;
export function containsAsyncOption<T>(
value: T,
r: Promise<IOption<T>>,
): Promise<boolean>;

Defined in: promise-option/containsAsyncOption.ts

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

Returns true if the Promise<IOption> is Some and the predicate holds. Returns false on None or when the predicate does not hold.

Throw policy: If the predicate throws synchronously or returns a rejected Promise, the error is caught and the result converts to false (canonical catch+convert policy — see AGENTS.md).

export function existsAsyncOption<T>(
predicate: (a: T) => boolean | Promise<boolean>,
): (r: Promise<IOption<T>>) => Promise<boolean>;
export function existsAsyncOption<T>(
predicate: (a: T) => boolean | Promise<boolean>,
r: Promise<IOption<T>>,
): Promise<boolean>;

Defined in: promise-option/existsAsyncOption.ts

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

Filters the value of a Promise<IOption<T>> with a predicate. Keeps the Some if the predicate holds; converts to None otherwise. None passes through.

Throw policy: If the predicate throws synchronously or returns a rejected Promise, the error is caught and the result converts to None (canonical catch+convert policy — see AGENTS.md).

export function filterAsyncOption<T>(
predicate: (a: T) => boolean | Promise<boolean>,
): (r: Promise<IOption<T>>) => Promise<IOption<T>>;
export function filterAsyncOption<T>(
predicate: (a: T) => boolean | Promise<boolean>,
r: Promise<IOption<T>>,
): Promise<IOption<T>>;

Defined in: promise-option/filterAsyncOption.ts

import { filterAsyncOption, ofSome } from '@sandlada/result/promise-option';
const r = await filterAsyncOption(async (x: number) => x > 10, Promise.resolve(ofSome(21)));
// Some(21)

Flattens a nested Promise<IOption<IOption<T>>>.

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

export function flattenAsyncOption<T>(
r: Promise<IOption<IOption<T>>>,
): Promise<IOption<T>>;

Defined in: promise-option/flattenAsyncOption.ts

import { flattenAsyncOption, ofSome } from '@sandlada/result/promise-option';
const r = await flattenAsyncOption(Promise.resolve(ofSome(ofSome(42)))); // Some(42)
const r2 = await flattenAsyncOption(Promise.resolve(ofSome(ofSome(ofSome(7))))); // Some(Some(7))

Transforms the value of a Promise<IOption<T>>. The callback may be sync or async.

Throw policy: if f throws synchronously or its returned Promise rejects, the result is None. The thrown reason is discarded.

export function mapAsyncOption<T, U>(
f: (a: T) => U | Promise<U>,
): (r: Promise<IOption<T>>) => Promise<IOption<U>>;
export function mapAsyncOption<T, U>(
f: (a: T) => U | Promise<U>,
r: Promise<IOption<T>>,
): Promise<IOption<U>>;

Defined in: promise-option/mapAsyncOption.ts

import { mapAsyncOption } from '@sandlada/result/promise-option';
import { ofSome } from '@sandlada/result/promise-option';
await mapAsyncOption((x: number) => x * 2, Promise.resolve(ofSome(21))); // Some(42)

Maps the value of Promise<IOption<T>>, returning a default on None. Mirrors mapOrAsync for the Option-flavored pipeline.

export function mapOrAsyncOption<A, B>(
defaultValue: B,
fn: (a: A) => B | Promise<B>,
): (r: Promise<IOption<A>>) => Promise<B>;
export function mapOrAsyncOption<A, B>(
defaultValue: B,
fn: (a: A) => B | Promise<B>,
r: Promise<IOption<A>>,
): Promise<B>;

Defined in: promise-option/mapOrAsyncOption.ts

import { mapOrAsyncOption } from '@sandlada/result/promise-option';
import { ofSome, ofNone } from '@sandlada/result/promise-option';
await mapOrAsyncOption(-1, (x: number) => x * 2, Promise.resolve(ofSome(21))); // 42
await mapOrAsyncOption(-1, (x: number) => x * 2, Promise.resolve(ofNone())); // -1

Maps the value of Promise<IOption<T>>, or computes a default from a thunk on None. Mirrors mapOrElseAsync for the Option-flavored pipeline.

export function mapOrElseAsyncOption<A, B>(
onNone: () => B | Promise<B>,
fn: (a: A) => B | Promise<B>,
): (r: Promise<IOption<A>>) => Promise<B>;
export function mapOrElseAsyncOption<A, B>(
onNone: () => B | Promise<B>,
fn: (a: A) => B | Promise<B>,
r: Promise<IOption<A>>,
): Promise<B>;

Defined in: promise-option/mapOrElseAsyncOption.ts

import { mapOrElseAsyncOption } from '@sandlada/result/promise-option';
import { ofSome, ofNone } from '@sandlada/result/promise-option';
await mapOrElseAsyncOption(() => -1, (x: number) => x * 2, Promise.resolve(ofSome(21))); // 42
await mapOrElseAsyncOption(() => -1, (x: number) => x * 2, Promise.resolve(ofNone())); // -1

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

export function matchAsyncOption<T, U>(
onSome: (a: T) => U | Promise<U>,
onNone: () => U | Promise<U>,
): (r: Promise<IOption<T>>) => Promise<U>;
export function matchAsyncOption<T, U>(
onSome: (a: T) => U | Promise<U>,
onNone: () => U | Promise<U>,
r: Promise<IOption<T>>,
): Promise<U>;

Defined in: promise-option/matchAsyncOption.ts

import { matchAsyncOption } from '@sandlada/result/promise-option';
import { ofSome } from '@sandlada/result/promise-option';
await matchAsyncOption(
(v: number) => `some: ${v}`,
() => `none`,
Promise.resolve(ofSome(42)),
); // "some: 42"

Error recovery for async options.

Throw policy: if f throws synchronously or its returned Promise rejects, the result is None. The thrown reason is discarded.

export function orElseAsyncOption<T>(
f: () => IOption<T> | Promise<IOption<T>>,
): (r: Promise<IOption<T>>) => Promise<IOption<T>>;
export function orElseAsyncOption<T>(
f: () => IOption<T> | Promise<IOption<T>>,
r: Promise<IOption<T>>,
): Promise<IOption<T>>;

Defined in: promise-option/orElseAsyncOption.ts

import { orElseAsyncOption } from '@sandlada/result/promise-option';
import { ofSome, ofNone } from '@sandlada/result/promise-option';
await orElseAsyncOption(
() => Promise.resolve(ofSome(0)),
Promise.resolve(ofNone()),
);

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

Throw policy: if fn throws synchronously or its returned Promise rejects, the result is None. The thrown reason is discarded.

export function tapAsyncOption<T>(
fn: (a: T) => void | Promise<void>,
): (r: Promise<IOption<T>>) => Promise<IOption<T>>;
export function tapAsyncOption<T>(
fn: (a: T) => void | Promise<void>,
r: Promise<IOption<T>>,
): Promise<IOption<T>>;

Defined in: promise-option/tapAsyncOption.ts

import { tapAsyncOption } from '@sandlada/result/promise-option';
import { ofSome } from '@sandlada/result/promise-option';
await tapAsyncOption((v: number) => console.log(v), Promise.resolve(ofSome(42)));

Side-effect on the error track of Promise<IOption<T>>.

Two callbacks: fn runs on the Some branch (with the inner value), fnNone runs on the None branch. Splitting the callbacks eliminates the (value: T | undefined) lie — on None there is genuinely no value, so the callback can’t pretend to receive one.

Throw policy: a synchronous throw from either callback converts to None; a rejected Promise propagates as an outer rejection (promotion-family rule).

export function tapErrAsyncOption<T>(
fn: (value: T) => void | Promise<void>,
fnNone?: () => void | Promise<void>,
): (r: Promise<IOption<T>>) => Promise<IOption<T>>;
export function tapErrAsyncOption<T>(
fn: (value: T) => void | Promise<void>,
r: Promise<IOption<T>>,
fnNone?: () => void | Promise<void>,
): Promise<IOption<T>>;

Defined in: promise-option/tapErrAsyncOption.ts

import { tapErrAsyncOption } from '@sandlada/result/promise-option';
import { ofNone } from '@sandlada/result/option';
await tapErrAsyncOption(
(v: number) => console.log('value:', v),
Promise.resolve(ofNone<number>()),
() => console.warn('absent'),
);

Extracts the value on success from an async option, or returns a default on failure.

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

export function unwrapOrAsyncOption<T, D = T>(
defaultValue: D | Promise<D>,
): (r: Promise<IOption<T>>) => Promise<T | D>;
export function unwrapOrAsyncOption<T, D>(
defaultValue: D | Promise<D>,
r: Promise<IOption<T>>,
): Promise<T | D>;

Defined in: promise-option/unwrapOrAsyncOption.ts

import { unwrapOrAsyncOption } from '@sandlada/result/promise-option';
import { ofSome, ofNone } from '@sandlada/result/promise-option';
await unwrapOrAsyncOption(0, Promise.resolve(ofSome(42))); // 42
await unwrapOrAsyncOption(0, Promise.resolve(ofNone())); // 0

Lazily extracts the value of Promise<IOption<T>>, computing a default from a thunk on None. Returns Promise<T | D>. Mirrors unwrapOrElseAsync for the Option-flavored pipeline.

The default value type D is independent of the success type T.

export function unwrapOrElseAsyncOption<T, D = T>(
onNone: () => D | Promise<D>,
): (r: Promise<IOption<T>>) => Promise<T | D>;
export function unwrapOrElseAsyncOption<T, D>(
onNone: () => D | Promise<D>,
r: Promise<IOption<T>>,
): Promise<T | D>;

Defined in: promise-option/unwrapOrElseAsyncOption.ts

import { unwrapOrElseAsyncOption } from '@sandlada/result/promise-option';
import { ofSome, ofNone } from '@sandlada/result/promise-option';
await unwrapOrElseAsyncOption(() => 0, Promise.resolve(ofSome(42))); // 42
await unwrapOrElseAsyncOption(() => 0, Promise.resolve(ofNone())); // 0

Re-exports asyncErr


Re-exports asyncOk


Re-exports ofNone


Re-exports ofSome