Skip to main content
These helpers let you work with multiple Result or ResultAsync values at once — collecting, racing, or combining them into a single result.

chas.all(results)

Returns Ok with an array of all values if every result is Ok, or short-circuits with the first Err encountered.
results
Iterable<Result<T, E>>
required
An array or iterable of results.
returns
Result<T[], E>
Ok([...values]) when all inputs are Ok, or the first Err.
const result = chas.all([chas.ok(1), chas.ok(2), chas.ok(3)]);
// Ok([1, 2, 3])

const failed = chas.all([chas.ok(1), chas.err('oops'), chas.ok(3)]);
// Err('oops') — stops at first Err

chas.allAsync(resultAsyncs)

The async counterpart to chas.all. Concurrently awaits all inputs and returns Ok with all values, or the first Err.
resultAsyncs
Iterable<PromiseLike<Result<T, E>>>
required
An array or iterable of ResultAsync values or promise-like results.
returns
ResultAsync<T[], E>
Resolves to Ok([...values]) when all inputs are Ok, or the first Err.
const result = await chas.allAsync([
  chas.okAsync(1),
  chas.okAsync(2),
]);
// Ok([1, 2])

chas.collect(results)

Like chas.all, but does not short-circuit. Collects all errors instead of stopping at the first one. Returns Ok with all values if every result is Ok, or Err with an array of every error encountered. Prefer this over chas.all in validation scenarios where you want to surface every failure at once.
results
Iterable<Result<T, E>>
required
An array or iterable of results.
returns
Result<T[], E[]>
Ok([...values]) or Err([...errors]).
const result = chas.collect([
  chas.ok(1),
  chas.err('too short'),
  chas.err('invalid email'),
]);
// Err(['too short', 'invalid email'])

chas.collectAsync(resultAsyncs)

The async counterpart to chas.collect. Concurrently awaits all inputs and collects every error.
resultAsyncs
Iterable<PromiseLike<Result<T, E>>>
required
An array or iterable of ResultAsync values or promise-like results.
returns
ResultAsync<T[], E[]>
Resolves to Ok([...values]) or Err([...errors]).
const result = await chas.collectAsync([
  chas.okAsync(1),
  chas.errAsync('a'),
  chas.errAsync('b'),
]);
// Err(['a', 'b'])

chas.any(results)

Returns the first Ok encountered, or Err with an array of all errors if every result is Err. The inverse of chas.all.
results
Iterable<Result<T, E>>
required
An array or iterable of results.
returns
Result<T, E[]>
The first Ok, or Err([...errors]) if all inputs fail.
const result = chas.any([
  chas.err('a'),
  chas.ok(2),
  chas.err('c'),
]);
// Ok(2)

const allFailed = chas.any([chas.err('a'), chas.err('b')]);
// Err(['a', 'b'])

chas.anyAsync(resultAsyncs)

The async counterpart to chas.any. Concurrently awaits all inputs and returns the first Ok, or all errors.
resultAsyncs
Iterable<PromiseLike<Result<T, E>>>
required
An array or iterable of ResultAsync values or promise-like results.
returns
ResultAsync<T, E[]>
Resolves to the first Ok, or Err([...errors]) if all inputs fail.
const result = await chas.anyAsync([
  chas.errAsync('a'),
  chas.okAsync(2),
]);
// Ok(2)

chas.race(results)

Returns the first result in the iterable, regardless of whether it is Ok or Err. In synchronous contexts this is always the first element since inputs are evaluated left-to-right.
results
Iterable<Result<T, E>>
required
An array or iterable of results.
returns
Result<T, E>
The first result encountered.
Throws if called with an empty iterable. Always pass at least one result.
chas.race([chas.err('a'), chas.ok(2)]); // Err('a')
chas.race([chas.ok(1), chas.err('b')]); // Ok(1)

chas.raceAsync(resultAsyncs)

Returns a ResultAsync that settles with whichever input resolves first — the async equivalent of Promise.race.
resultAsyncs
Iterable<PromiseLike<Result<T, E>>>
required
An array or iterable of ResultAsync values or promise-like results.
returns
ResultAsync<T, E>
Resolves with the first input to settle, whether Ok or Err.
const result = await chas.raceAsync([
  chas.fromPromise(slowQuery(), e => String(e)),
  chas.fromPromise(fastQuery(), e => String(e)),
]);
// Whichever resolves first

chas.shapeAsync(record)

Concurrently awaits an object whose values are ResultAsync values and returns a single ResultAsync containing an object with the same keys mapped to their Ok values, or the first Err encountered. Use this to fan out parallel async operations with named keys.
record
Record<string, ResultAsync<T, E> | PromiseLike<Result<T, E>>>
required
An object mapping string keys to async results.
returns
ResultAsync<{ [K in keyof record]: T }, E>
Resolves to a shaped object of all Ok values, or the first Err.
const result = await chas.shapeAsync({
  user: fetchUser(id),
  posts: fetchPosts(id),
  settings: fetchSettings(id),
});

if (result.isOk()) {
  const { user, posts, settings } = result.value;
}

chas.go(generatorFn)

Do-notation for Result. Runs a generator function where each yield* result unwraps the Ok value or immediately short-circuits with the Err. This lets you write sequential, imperative-looking code without nested .andThen chains. Pass a sync generator (function* () {}) to get a Result, or an async generator (async function* () {}) to get a ResultAsync. Yielding a ResultAsync inside a sync generator automatically upgrades the return type to ResultAsync.
generatorFn
() => Generator | AsyncGenerator
required
A generator or async generator function that yields results via yield*.
returns
Result<T, E> | ResultAsync<T, E>
The final return value wrapped in Ok, or the first Err that caused a short-circuit.
See the do-notation recipe for a deeper guide.
// Synchronous
const result = chas.go(function* () {
  const user = yield* fetchUser(1);           // Err short-circuits here
  const profile = yield* fetchProfile(user);
  return { user, profile };                   // Wrapped in Ok automatically
});

// Asynchronous
const asyncResult = await chas.go(async function* () {
  const user = yield* fetchUserAsync(1);
  const profile = yield* fetchProfileAsync(user.id);
  return { user, profile };
});