question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Err.andThen always returns a Result which prevents transforming a Result to a ResultAsync

See original GitHub issue

The current andThen overloaded methods in Ok and Err look like this:

export declare class Ok<T, E> {
    andThen<U>(f: (t: T) => ResultAsync<U, E>): ResultAsync<U, E>;
    andThen<U>(f: (t: T) => Result<U, E>): Result<U, E>;
}
export declare class Err<T, E> {
    andThen<U>(_f: (t: T) => Result<U, E>): Result<U, E>;
    andThen<U>(_f: (t: T) => ResultAsync<U, E>): Result<U, E>;
}

Which seems to prevent me from doing things like this:

const sq = (n: number): Result<number, number> => ok(n ** 2);
const sqAsync = (n: number): ResultAsync<number, number> => okAsync(n ** 2);

ok(2)
  .andThen(sq)
  // ERROR
  // Argument of type '(n: number) => ResultAsync<number, number>' is not assignable to parameter of type '(t: number) => Result<unknown, unknown>'.
  // Type 'ResultAsync<number, number>' is not assignable to type 'Result<unknown, unknown>'.
  // Type 'ResultAsync<number, number>' is missing the following properties from type 'Err<unknown, unknown>': error, isOk, isErr, asyncMap, and 2 more.ts(2345)
  .andThen(sqAsync);

The above error message isn’t that useful but if you rename async andThen methods to andTest as such:

export declare class Ok<T, E> {
    andTest<U>(f: (t: T) => ResultAsync<U, E>): ResultAsync<U, E>;
    andThen<U>(f: (t: T) => Result<U, E>): Result<U, E>;
}
export declare class Err<T, E> {
    andThen<U>(_f: (t: T) => Result<U, E>): Result<U, E>;
    andTest<U>(_f: (t: T) => ResultAsync<U, E>): Result<U, E>;
}

and then change the example code above:

const sq = (n: number): Result<number, number> => ok(n ** 2);
const sqAsync = (n: number): ResultAsync<number, number> => okAsync(n ** 2);

ok(2)
  .andThen(sq)
  .andTest(sqAsync);

you get the following error:

This expression is not callable.
  Each member of the union type '(<U>(f: (t: number) => ResultAsync<U, unknown>) => ResultAsync<U, unknown>) | (<U>(_f: (t: number) => ResultAsync<U, unknown>) => Result<U, unknown>)' has signatures, but none of those signatures are compatible with each other.ts(2349) 

How can I take a Result and turn it into a ResultAsync when I have an operation that returns a Promise?

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:9 (9 by maintainers)

github_iconTop GitHub Comments

3reactions
supermacrocommented, Jun 16, 2020

v2.4.0 is now live on npm

2reactions
supermacrocommented, Jun 15, 2020

Hey @jsmith @paduc,

Here are my thoughts.

I also agree that andThen (as well as any method in neverthrow) should always have the same method signature across Ok and Err instances (maybe something I should add to a contributing guidelines document).

When originally doing code review for the introduction of ResultAsync, I overlooked this subtlety, but if I hadn’t overlooked it, I would have made the point above.

I’m thinking that maybe Result.andThen should only accept _f: (t: T) => Result<U, E> functions and we should create a separate Result.asyncAndThen for when we need to chain async methods (the same we did for map/asyncMap).

I actually really like this overloaded behaviour. It reduces the surface area of API, but makes the current API multi-purpose.

I’m not sure how to implement Err.andThen in a manner that returns a ResultAsync though.

I can dive into the code later today and open a PR that does this. I’m fairly confident I can implement something that works.

If it cannot be done then I may be open to adding a asyncAndThen method.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to use neverthrow with async/await through the call ...
I am currently replacing my pure Promise structure by ResultAsync. ... with async function you can just return error result right away.
Read more >
Optional, throws, Result, async/await - NSHipster
We set up a query, pass an an empty inout reference to SecItemCopyMatching and then, depending on the status code we get back,...
Read more >
neverthrow - npm
This package contains a Result type that represents either success ( Ok ) or failure ( Err ). For asynchronous tasks, neverthrow offers...
Read more >
Discussion of Type-Safe Error Handling In TypeScript
You've changed your one "if not url, return the err result" line to not ... on any third-party libraries, there'll always be throw...
Read more >
Frequently Asked Questions - Jasmine Documentation
How can I stop Jasmine from running my specs in parallel? ... the access to result.things.length will throw an error, preventing done from...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found