Conversation
- Add Result<T, E> union type - Add ok() and err() constructors - Add isOk() and isErr() type guards with methods - Add map(), flatMap(), mapErr() transformations - Add getOrElse(), getOrCompute() extraction - Add tap(), match() for side effects and pattern matching - Add toNullable(), toUndefined() conversions - 43 tests with 100% coverage Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add Try<T, E> union type - Add attempt() for sync try/catch - Add attemptAsync() for async try/catch - Add isOk() and isErr() type guards - Add map(), flatMap() transformations - Add getOrElse(), getOrCompute() extraction - Add tap(), match() for side effects - Add toNullable(), toUndefined() conversions - 27 tests with 100% coverage Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add AsyncResult<T, E> type (Promise of Ok/Err) - Add okAsync() and errAsync() constructors - Add fromPromise() to convert Promise to AsyncResult - Add isOk() and isErr() type guards - Add map(), flatMap() sync transformations - Add mapAsync(), flatMapAsync() async transformations - Add getOrElse(), getOrCompute() extraction - Add tap(), match() for side effects - Add race(), all(), traverse() parallel utilities - Add toNullable(), toUndefined() conversions - 32 tests with 100% coverage Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| * @param value - The success value | ||
| * @returns Promise<AsyncOk<T>> | ||
| */ | ||
| export const okAsync = <T>(value: T): AsyncResult<T, never> => |
There was a problem hiding this comment.
The okAsync and errAsync functions don't freeze the returned objects, unlike the synchronous ok and err functions in result.ts which use Object.freeze(). This is an inconsistency that could lead to unexpected mutations.
| const r = await result; | ||
| return isOk(r) ? ok(r.value) : err(r.error); | ||
| }; | ||
|
|
There was a problem hiding this comment.
The mapErr function is missing from AsyncResult. The synchronous Result type has mapErr (result.ts:122-123) to transform errors, but AsyncResult doesn't have this utility. Consider adding mapErr and mapErrAsync functions.
| * AsyncOk type - represents a successful async result | ||
| * @typeParam T - The type of the value | ||
| */ | ||
| export type AsyncOk<T> = { |
There was a problem hiding this comment.
The AsyncOk and AsyncErr types don't include isOk() and isErr() methods that exist on the synchronous Ok and Err types (result.ts:20-21, 30-32). This is a minor inconsistency in the API design.
| * @param promise - The promise to convert | ||
| * @returns AsyncResult<T, Error> | ||
| */ | ||
| export const fromPromise = <T>(promise: Promise<T>): AsyncResult<T, Error> => |
There was a problem hiding this comment.
The default error type is Error which differs from other error types that might be used. This is reasonable but users should be aware they can specify a more specific error type with fromPromise<number, CustomErrorType>.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| * @param value - The success value | ||
| * @returns Promise<AsyncOk<T>> | ||
| */ | ||
| export const okAsync = <T>(value: T): AsyncResult<T, never> => |
There was a problem hiding this comment.
The sync Result type uses Object.freeze() to make objects immutable (see result.ts:40-50 and result.ts:57-67), but the async versions (okAsync and errAsync in async-result.ts:41-56) don't freeze the returned objects. Consider adding Object.freeze() for consistency.
| * @typeParam T - The type of the success value | ||
| * @typeParam E - The type of the error | ||
| */ | ||
| export type AsyncResult<T, E = Error> = Promise<AsyncResultInner<T, E>>; |
There was a problem hiding this comment.
The sync Result type includes isOk() and isErr() methods on the Ok and Err types (see result.ts:20-21 and result.ts:31-32). The AsyncResult type doesn't include these methods. Consider adding them for API consistency.
| * @param result - The AsyncResult to check | ||
| * @returns true if AsyncResult is AsyncErr<E> | ||
| */ | ||
| export const isErr = <T, E>(result: AsyncResultInner<T, E>): result is AsyncErr<E> => |
There was a problem hiding this comment.
The sync Result type has a mapErr function (result.ts:122-123) to transform errors. AsyncResult is missing a corresponding mapErr (both sync and async versions). Consider adding mapErr and mapErrAsync functions.
| * @param results - The AsyncResults to race | ||
| * @returns Promise<T> - The value of the first resolved | ||
| */ | ||
| export const race = <T, E>(...results: Array<AsyncResult<T, E>>): Promise<T> => |
There was a problem hiding this comment.
The race function throws when encountering an error. This could be problematic in some use cases where you'd want to handle errors differently. Consider documenting this behavior clearly or providing a variant that returns AsyncResult<T, E> instead of throwing.
The getOrCompute function was returning T | Promise<U> inside Promise.then(), which TypeScript couldn't properly type. Changed to use async/await for proper type inference. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| * AsyncOk type - represents a successful async result | ||
| * @typeParam T - The type of the value | ||
| */ | ||
| export type AsyncOk<T> = { |
There was a problem hiding this comment.
The AsyncOk and AsyncErr types don't have isOk() and isErr() methods, unlike the sync Ok and Err types in result.ts. This is an inconsistency in the API. Consider adding these methods for consistency.
| * @param value - The success value | ||
| * @returns Promise<AsyncOk<T>> | ||
| */ | ||
| export const okAsync = <T>(value: T): AsyncResult<T, never> => |
There was a problem hiding this comment.
The sync ok constructor (result.ts:40-50) uses Object.freeze() to make the result immutable, but the async okAsync constructor doesn't. Consider adding Object.freeze() for consistency.
| * @param fn - The async mapping function | ||
| * @returns AsyncResult<U, E> | ||
| */ | ||
| export const mapAsync = async <T, E, U>( |
There was a problem hiding this comment.
The sync Result type has a mapErr function (result.ts:122-123) to transform errors, but AsyncResult doesn't have an equivalent. Consider adding mapErr and mapErrAsync functions for completeness.
| }); | ||
| }); | ||
|
|
||
| describe("mapAsync", () => { |
There was a problem hiding this comment.
The PR description mentions 100% test coverage with 32 tests, but I count ~30 tests in this file. Missing edge case tests: (1) mapAsync when the async function throws, (2) flatMapAsync returning an error, (3) race when one result errors before another resolves.
| * @param results - The AsyncResults to race | ||
| * @returns Promise<T> - The value of the first resolved | ||
| */ | ||
| export const race = <T, E>(...results: Array<AsyncResult<T, E>>): Promise<T> => |
There was a problem hiding this comment.
The race function behavior when mixing successes and errors may be non-deterministic. Consider documenting the exact behavior or adding a variant (e.g., raceOk) that only resolves on success and ignores errors.
Summary
Add AsyncResult type for async railway-oriented programming - chaining asynchronous operations with proper error handling.
Changes
Types
{ ok: true, value: T }{ ok: false, error: E }Constructors
Chaining
Parallel Operations
Coverage
100% test coverage. 32 tests.
🤖 Generated with Claude Code