Skip to content

Commit

Permalink
Fix an AsyncResult.andThen fix-related regression (#195)
Browse files Browse the repository at this point in the history
This patch reverts commit [1] and documents this fact.

The problem is after [1] the following code

    const fromRegularResult = (Ok(1) as Result<number, string>).toAsyncResult();
    fromRegularResult.andThen((value) => Ok(value * 2));

would fail co compile:

    src/file.ts:169:19 - error TS2349: This expression is not callable.
      Each member of the union type '{ <T2>(mapper: (val: never) => Ok<T2> | Promise<Ok<T2>> | AsyncResult<T2, never>): AsyncResult<T2, string>; <T2, E2>(mapper: (val: never) => Result<...> | ... 1 more ... | AsyncResult<...>): AsyncResult<...>; } | { ...; }' has signatures, but none of those signatures are compatible with each other.

    169 fromRegularResult.andThen((value) => Ok(value * 2));
                          ~~~~~~~

    src/file.ts:169:28 - error TS7006: Parameter 'value' implicitly has an 'any' type.

    169 fromRegularResult.andThen((value) => Ok(value * 2));
                                   ~~~~~

I spent the last Friday's afternoon trying to figure out why and how to
fix it and I failed. I think reverting the original patch is the way to
go for now and it was handling an edge case anyway.

It's more important that andThen works in general cases (where the
callbacks return Result, not always Ok).

[1] 9259f83 ("Fix the AsyncResult.andThen handling of known-Ok transformations (#189)")
  • Loading branch information
jstasiak authored Feb 10, 2025
1 parent e1769e0 commit 45aaa47
Show file tree
Hide file tree
Showing 3 changed files with 11 additions and 13 deletions.
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# 5.0.1 (not released yet)

Fixed:

- Fixed the regression introduced in 5.0.0 as part of the `AsyncResult.andThen` fix. The fix
is completely reverted for now.

# 5.0.0

Backwards incompatible:
Expand Down Expand Up @@ -25,8 +32,9 @@ Fixed:

- Fixed `Result.or` and `Result.orElse` method types to actually be callable and return
reasonable types when called.
- Fixed `AsyncResult.andThen` to return the correct type when the provided callback
- Attempted to fix `AsyncResult.andThen` to return the correct type when the provided callback
always returns an `Ok`.
This attempt has been (for now) reverted in 5.0.1 as it created other problems.
- Fixed the `Result.partition` signature.

Added:
Expand Down
4 changes: 0 additions & 4 deletions src/asyncresult.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,6 @@ export class AsyncResult<T, E> {
* await badResult.andThen(async (value) => Ok(value * 2)).promise // Err('boo')
* ```
*/
andThen<T2>(mapper: (val: T) => Ok<T2> | Promise<Ok<T2>> | AsyncResult<T2, never>): AsyncResult<T2, E>;
andThen<T2, E2>(
mapper: (val: T) => Result<T2, E2> | Promise<Result<T2, E2>> | AsyncResult<T2, E2>,
): AsyncResult<T2, E | E2>;
andThen<T2, E2>(
mapper: (val: T) => Result<T2, E2> | Promise<Result<T2, E2>> | AsyncResult<T2, E2>,
): AsyncResult<T2, E | E2> {
Expand Down
10 changes: 2 additions & 8 deletions test/asyncresult.test.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { AsyncResult, Err, Ok, Result, Some } from '../src/index.js';
import { eq } from './util.js';
import { AsyncResult, Err, Ok, Some } from '../src/index.js';

test('andThen() should work', async () => {
const err = Err('error');
const badResult = new AsyncResult(err);
const goodResult = new AsyncResult(Ok(100) as Result<number, string>);
const goodResult = new AsyncResult(Ok(100));

expect(
await badResult.andThen(() => {
Expand All @@ -13,11 +12,6 @@ test('andThen() should work', async () => {
).toEqual(err);
expect(await goodResult.andThen((value) => Promise.resolve(Ok(value * 2))).promise).toEqual(Ok(200));
expect(await goodResult.andThen((value) => Ok(value * 3).toAsyncResult()).promise).toEqual(Ok(300));

const afterAndThenOk = goodResult.andThen((value) => Promise.resolve(Ok(value * 2)));
eq<typeof afterAndThenOk, AsyncResult<number, string>>(true);
const afterAndThenResult = goodResult.andThen(() => Ok(true) as Result<boolean, boolean>);
eq<typeof afterAndThenResult, AsyncResult<boolean, string | boolean>>(true);
});

test('map() should work', async () => {
Expand Down

0 comments on commit 45aaa47

Please sign in to comment.