Skip to main content

Overview

better-result provides first-class support for asynchronous operations through Result.tryPromise, Result.await, and async generator composition. This enables Railway-Oriented Programming patterns with async/await syntax.

Handling Promises with tryPromise

The Result.tryPromise function wraps promise-based operations, converting rejections into Err values:

Custom Error Handling

Provide a catch handler to transform exceptions into typed errors:
The catch handler can be async, allowing you to enrich errors with additional context from external sources (databases, caches, etc.).

Async Generator Composition with Result.await

The Result.await function makes Promise<Result> values yieldable in async generators:

How Result.await Works

Under the hood, Result.await is an async generator that awaits the promise and yields the result:
When used with yield*, it unwraps Ok values and short-circuits on Err.

Async Combinators

andThenAsync

Chain async Result-returning functions:

tapAsync

Perform async side effects without changing the Result:
If the async callback in tapAsync throws or rejects, it results in a Panic. Use Result.tryPromise inside tapAsync if the side effect can fail.

Parallel Operations

Execute multiple async operations concurrently and collect results:

Promise.all with Results

Partition for Batch Operations

Use Result.partition to separate successes from failures:

Fail-Fast vs Collect-All

Stop at the first error using Result.gen:

Real-World Patterns

API Request Pipeline

Database Transaction Flow

Streaming Data Processing

Testing Async Operations

Best Practices

1

Always await Result.tryPromise

Result.tryPromise returns a Promise<Result>, not a Result. Don’t forget the await.
2

Use Result.await in async generators

When working with Promise<Result> in Result.gen, use Result.await to make it yieldable.
3

Provide typed error handlers

Use the { try, catch } form to transform exceptions into typed errors for better type safety.
4

Consider parallelization

Use Promise.all with Result.tryPromise for independent operations to improve performance.
5

Handle partial failures gracefully

Use Result.partition to process successful results even when some operations fail.
Async operations in Result.gen short-circuit on the first error. If you need to collect all errors, fetch results in parallel first, then process them in the generator.