Primitives: cond, sequence, reduce
Primitives — barrel export.
Re-exports small but commonly-missing helpers: cond, condErr, sequence,
sequenceAsyncResult, reduce, partitionOption, lift.
Interfaces
Section titled “Interfaces”Partitioned
Section titled “Partitioned”Defined in: primitives/partitionOption.ts:26
partitionOption — splits an array of IOption<T> into its Some
values and the indices of Nones. The index array is preserved so callers
can match the original list (useful when validating a fixed-shape schema).
Unlike separate, which partitions IResultOfT into Ok/Err values,
partitionOption returns only Some values plus the indices of Nones
(because None carries no payload to preserve). If you need the None
indices for IResultOfT, use combineWithAllErrors instead.
Example
Section titled “Example”import { partitionOption, cond } from '@sandlada/result/primitives';import { ofSome, ofNone } from '@sandlada/result/option';import { match } from '@sandlada/result/operators';
const opts = [ofSome(1), ofNone(), ofSome(3), ofNone()];const parts = partitionOption(opts);const validated = cond((n: number) => n === 2, 'expected two Some values', parts.some.length);const count = match((n) => String(n), (e) => e, validated);// parts.some is [1, 3]; parts.noneIndices is [1, 3]; count === 2 on successType Parameters
Section titled “Type Parameters”| Type Parameter |
|---|
T |
Properties
Section titled “Properties”| Property | Modifier | Type |
|---|---|---|
noneIndices |
readonly |
readonly number[] |
some |
readonly |
readonly T[] |
Functions
Section titled “Functions”cond()
Section titled “cond()”cond — the value-aware form of fromPredicate. Returns Ok(value)
when the predicate passes, otherwise Err(errorOnFalse).
Unlike fromPredicate, cond always carries the original value through, so it
is the natural choice when the failure branch also needs the value (e.g. “value
not in allowed set” → Err({ value, allowed })).
If predicate(value) returns true, yields Ok(value); otherwise yields
Err(errorOnFalse).
export function cond<T, E>( predicate: (value: T) => boolean, errorOnFalse: E, value: T,): IResultOfT<T, E>;Defined in: primitives/cond.ts
Example
Section titled “Example”import { cond } from '@sandlada/result/primitives';import { match } from '@sandlada/result/operators';
const value = 5;const bad = -1;const passed = cond((n: number) => n > 0, 'must be positive', value);const failed = cond((n: number) => n > 0, 'must be positive', bad);const label = match((n) => String(n), (e) => e, passed);// label === '5'; failed is Err('must be positive') when the third argument fails the predicatecondErr()
Section titled “condErr()”condErr — the inverse of cond. When the predicate passes,
returns Err(errorOnTrue); otherwise returns Ok(okValue).
Use it when a presence condition should fail (e.g. “found a forbidden character → Err”).
export function condErr<T, E>( predicate: (value: T) => boolean, okValue: T, errorOnTrue: E,): IResultOfT<T, E>;Defined in: primitives/condErr.ts
Example
Section titled “Example”import { condErr } from '@sandlada/result/primitives';import { match } from '@sandlada/result/operators';
const invalid = 'alice@x';const valid = 'no-at';const rule = 'invalid email';const rejected = condErr((s: string) => s.includes('@'), invalid, rule);const accepted = condErr((s: string) => s.includes('@'), valid, rule);const label = match((s) => s, (e) => e, accepted);// rejected is Err(rule); label === 'no-at' when the second argument passes the predicatelift()
Section titled “lift()”lift — lift a (possibly throwing) function into the
IResultOfT context. This is the fromThrowable cousin that never marks
the failure channel: use it for synchronous, total functions where you want the
Result shape for pipeline uniformity without an error type.
If fn throws, the error is captured under the supplied errorFn. If no
errorFn is given, thrown errors propagate out of lift(...) itself (matching
unwrapOr’s documented throw policy).
Note on E = never: the single-argument overload has default error type
never. This reflects the type-level guarantee that the function never
produces an Err when no errorFn is supplied — but the function itself can
still throw at runtime, in which case the throw propagates synchronously to
the caller. If you want all errors funneled into the Err channel, supply
an errorFn.
export function lift<A extends unknown[], T, E = never>( fn: (...args: A) => T,): (...args: A) => IResultOfT<T, E>;export function lift<A extends unknown[], T, E>( fn: (...args: A) => T, errorFn: (error: unknown) => E,): (...args: A) => IResultOfT<T, E>;Defined in: primitives/lift.ts
Example
Section titled “Example”import { lift } from '@sandlada/result/primitives';import { match } from '@sandlada/result/operators';
const safeParseInt = lift((s: string) => Number.parseInt(s, 10), (e) => new Error(String(e)));const input = '21';const parsed = safeParseInt(input);const total = lift((n: number) => n * 2)(42);const label = match((n) => String(n), (e) => String(e), parsed);// label === 21; total is Ok(84); invalid strings map to Err via the errorFn argumentpartitionOption()
Section titled “partitionOption()”Single pass over opts, accumulating Some values and the indices of Nones.
export function partitionOption<T>(opts: readonly IOption<T>[]): Partitioned<T>;Defined in: primitives/partitionOption.ts
reduce()
Section titled “reduce()”reduce — fold a list of IResultOfT<T, E> into a single
IResultOfT<Acc, E> via a (acc, value, index) => IResultOfT<Acc, E> step.
Short-circuits on the first failure returned by either the source list or the
step function.
Folds items left-to-right. If any item is Err, the reducer is skipped and the
failure is returned. If the reducer itself returns Err, processing stops.
export function reduce<T, E, Acc>( reducer: (acc: Acc, value: T, index: number) => IResultOfT<Acc, E>, initial: Acc, items: readonly IResultOfT<T, E>[],): IResultOfT<Acc, E>;Defined in: primitives/reduce.ts
Example
Section titled “Example”import { reduce } from '@sandlada/result/primitives';import { ok, err } from '@sandlada/result/factories';import { match } from '@sandlada/result/operators';
const items = [ok(1), ok(2), ok(3)];const sum = reduce( (acc, n) => (n === 0 ? err('zero not allowed') : ok(acc + n)), 0, items,);const broken = reduce((acc, n) => ok(acc + n), 0, [ok(1), err('bad'), ok(3)]);const total = match((n) => String(n), (e) => e, sum);// total === 6; broken short-circuits to Err('bad') on the second item in the listsequence()
Section titled “sequence()”sequence — alias of combine. Provided for readers familiar
with Rust/Haskell where “sequence” means turning [Result<T, E>] into
Result<T[], E>. The behaviour is identical to combine; pick whichever name
matches your codebase’s vocabulary.
Converts [IResultOfT<T, E>] into IResultOfT<readonly T[], E>,
short-circuiting on the first failure. The readonly modifier matches
combine’s tuple-overload output for runtime-sized readonly arrays.
export function sequence<T, E>( results: readonly IResultOfT<T, E>[],): IResultOfT<readonly T[], E>;Defined in: primitives/sequence.ts
Example
Section titled “Example”import { sequence } from '@sandlada/result/primitives';import { ok, err } from '@sandlada/result/factories';import { match } from '@sandlada/result/operators';
const inputs = [ok(1), ok(2), ok(3)];const allOk = sequence(inputs);const short = sequence([ok(1), err('a'), ok(3)]);const values = match((arr) => arr.join(','), (e) => e, allOk);// values === '1,2,3'; short stays Err('a') without collecting the third resultsequenceAsyncResult()
Section titled “sequenceAsyncResult()”Lazy analogue of sequence. Converts AsyncResult<T, E>[]
into AsyncResult<T[], E> without executing any inner run(). The returned
thunk short-circuits on the first failure when finally awaited.
Equivalent to combine from @sandlada/result/async-result, exposed under a
name familiar to ROP practitioners.
export function sequenceAsyncResult<T, E>( results: readonly AsyncResult<T, E>[],): AsyncResult<T[], E>;Defined in: primitives/sequenceAsyncResult.ts
Example
Section titled “Example”import { sequenceAsyncResult } from '@sandlada/result/primitives';import { fromResult } from '@sandlada/result/async-result';import { ok } from '@sandlada/result/factories';import { match } from '@sandlada/result/operators';
const thunks = [fromResult(ok(1)), fromResult(ok(2))];const combined = sequenceAsyncResult(thunks);const r = await combined.run();const label = match((arr) => String(arr.length), (e) => e, r);// label === 2; the first Err from any inner run() short-circuits the batch