Combine parallel results
How-to. Collect several independent
Results into one. For dependent steps (each needs the previous value), use do-notation instead.
Combine an array with all
all collects a tuple/array of Results into a Result of all their values. The first Err short-circuits; any Defect dominates (even over an earlier Err). A fixed tuple keeps its positional types; a dynamic Result<T, E>[] collapses to Result<T[], E>:
import { all, Ok, type Result } from "unthrown";
all([Ok(1), Ok("two"), Ok(true)]).get(); // => [1, "two", true] (typed [number, string, boolean])
all([Ok(1), Ok(2)] as Result<number, never>[]).get(); // => number[]Combine a record with allFromDict
For named parallel work, allFromDict takes a record instead — same rules, no tupling:
import { allFromDict, Ok } from "unthrown";
allFromDict({ id: Ok(1), name: Ok("ada") }).get(); // => { id: 1, name: "ada" }Both short-circuit on the first Err — this is not error accumulation (see Design decisions).
Combine async results concurrently
allAsync and allFromDictAsync are the asynchronous counterparts — same folding rules, inputs resolved concurrently (order preserved), and (like every AsyncResult) they never reject:
import { allAsync } from "unthrown";
// loadProfile / loadPosts / loadFollowers each return an AsyncResult
const page = allAsync([loadProfile(id), loadPosts(id), loadFollowers(id)]);
// AsyncResult<[Profile, Post[], User[]], ProfileError>
page.map(([profile, posts, followers]) => renderPage(profile, posts, followers));Use allFromDictAsync to key the concurrent results by name instead of position.
Where to go next
- Sequence dependent steps: Sequence dependent steps.
- The full aggregate surface: Result & AsyncResult surface.