Skip to content
Zap Studio
monads
Esc
navigateopen⌘Jpreview
On this page

ResultAsync

A thenable wrapper around Promise<Result<T, E>> for chaining async operations that can fail.

ResultAsync<T, E> wraps a Promise<Result<T, E>>. It’s the one class in this package: it needs to be awaitable directly, and its combinators are instance methods so you can build an async chain before the final await. Result and Option stay plain discriminated unions with standalone functions — see Result and Option.

Creating a ResultAsync

fromPromise wraps a rejecting Promise, mapping the rejection reason into your error type:

import { fromPromise } from "@zap-studio/monads";

const user = fromPromise(
  fetch("/api/user").then((response) => response.json()),
  (error) => `request failed: ${String(error)}`,
);

Chaining

import { err, fromPromise, ok } from "@zap-studio/monads";

const greeting = fromPromise(
  fetch("/api/user").then((response) => response.json()),
  (error) => `request failed: ${String(error)}`,
)
  .map((user) => user.name)
  .andThen((name) => (name.length > 0 ? ok(`Hello, ${name}`) : err("empty name")));

andThen’s callback can return a Result, a Promise<Result>, or another ResultAsync — all three are awaited the same way.

Recovering

orElse is andThen’s counterpart for the failure side: it recovers an eventual Err, leaving an eventual Ok untouched. Its callback accepts the same three return shapes as andThen’s:

const withFallback = fromPromise(
  fetch("/api/user").then((response) => response.json()),
  (error) => `request failed: ${String(error)}`,
).orElse((reason) =>
  fromPromise(
    fetch("/api/user/default").then((response) => response.json()),
    () => reason,
  ),
);

Resolving

ResultAsync is awaitable directly, resolving to the wrapped Result:

const result = await user; // Result<User, string>

Or fold it with match, which returns a Promise of the matched value:

const message = await user.match({
  ok: (u) => `Hello, ${u.name}`,
  err: (reason) => reason,
});

Last updated on September 21, 2026

Was this page helpful?