Overview
Result.gen() enables imperative-style error handling using JavaScript generators and yield* syntax:
- Write code that looks synchronous but short-circuits on first error
- Automatic error type union inference across multiple yields
- Support for
finallyblocks,usingdeclarations, and async operations - Type-safe alternative to try-catch and promise chaining
Basic Usage
Simple Composition
Short-Circuiting on Error
When anyyield* encounters an Err, execution stops immediately:
This is railway-oriented programming: operations proceed on the “success track” until an error switches to the “error track”.
How It Works
The yield* Operator
yield* delegates to the iterator protocol. Ok and Err implement [Symbol.iterator]:
Result.gen() encounters a yielded Err, it stops the generator and returns that error.
Type Inference
TypeScript infers the union of all yielded error types:Comparison to Other Patterns
vs Try-Catch
vs Promise Chaining
vs andThen Chaining
Async Generators
Result.await()
WrapPromise<Result> to make it yieldable in async generators:
Mixing Sync and Async
Error Propagation
Automatic Error Union
Errors from all yields are automatically unioned:Normalizing Error Types
UsemapError() to convert error unions to a single type:
Resource Cleanup
Finally Blocks
finally blocks run even when short-circuiting:
Using Declarations (Resource Management)
TC39 Explicit Resource Management (Stage 3) works withResult.gen():
Async Resource Management
Complex Control Flow
Conditional Logic
Loops
If any
yield* in the loop fails, the entire operation stops and returns that error.Early Returns
Context Binding
Bindthis context with the second parameter:
Real-World Examples
User Registration Flow
Batch Processing with Rollback
Multi-Step Workflow
Best Practices
Always return Result from generator
Always return Result from generator
The generator body must return
Result.ok() or Result.err():Don't throw in generators
Don't throw in generators
Throwing before any
yield* will cause a Panic:Ensure finally blocks don't throw
Ensure finally blocks don't throw
Wrap cleanup in try-catch:
Use Result.await for promises
Use Result.await for promises
Always wrap
Promise<Result> with Result.await():Summary
UseResult.gen() when you need:
- Imperative style - Code that reads like normal sync/async code
- Multiple values - Access to intermediate results
- Complex control flow - Conditions, loops, early returns
- Resource cleanup -
finallyblocks orusingdeclarations - Error union - Automatic inference of all possible error types
Result.gen() when:
- Simple linear transformations (use
map()/andThen()) - Purely functional composition (use pipeable API)
- No intermediate values needed
Next Steps
Creating Results
Learn how to create Result instances with ok, err, try, and tryPromise
Error Handling
Master TaggedError and exhaustive error matching