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.

Why can't I return different error types in a "andThen" chain?

See original GitHub issue

Hi,

Thank you for publishing this!

I wanted to get started right away but ran into a seemingly trivial problem I am too much of a noob to solve. Any help would be appreciated!

The compiler complains when I want to compose multiple results with the .andThen() method

type E1 = 'invalid'
type E2 = 'also invalid'
type E3 = 'invalid again'
type Errors = E1 | E2 | E3

const f1 = (sth: unknown) => Result<string, E1>
const f2 = (input: string) => Result<string, E2>
const f3 = (thing: string) => Result<string, E3>

const result: Result<string, Errors> = f1('test')
                         .andThen(f2)
                         .andThen(f3)

The compiler complains that that the result of f1 is not assignable to the result of f2, specifically Result<string, E1> is not assignable to Result<string, E2>.

I thought that the mismatch of results and function parameters wouldn’t hurt, because .andThen() doesn’t even call the next function if the result is of type Err. Any idea how I could help with the type inference?

Issue Analytics

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

github_iconTop GitHub Comments

4reactions
supermacrocommented, Jan 25, 2021

Alright folks … After 8 months of thinking through this, I think I am finally persuaded to go down the route of joining types.

I’m planning on doing some work soonish on this. Maybe I’ll get around to it this week.

I realized that because Rust and Haskell and basically all the other well-known languages that have a Result don’t have subtyping. So it’s literally impossible to do T | A … it’s just not part of those languages. But in typescript, this is allowed!

2reactions
realphacommented, Jun 19, 2020

Hi there, I’ve been following this discussion for quite a while now from the sidelines and I do understand @supermacro 's reservations (to some extend)

Going back to one of your past comments:

Yes, I could use a single error type E, add a type string literal to it like in my example above, and discriminate using the type property.

I still stand by this approach. Which is what I use when merging various error types in a long chain or results

This is definetely an idioamtic approach in most circumstances, and you are right that andThen or bind or however the equivalent is called in other languages doesn’t allow a different error type to be returned (AFAIK).

BUT this approach comes with a cost (and is also sometimes criticized in the respective communities): composability on the macro level can only be achieved by sacrifizing type expressiveness at the mirco level. @supermacro has demonstrated this in one of his previous examples pretty well. Compare: (modified from the OP)

type E1 = number
type E2 = string
interface E3 {
  errorCode: number
  message: string
}

type MyUnion = E1 | E2 | E3

type F1 = (sth: unknown) => Result<string, E1>;
type F2 = (sth2: string) => Result<string, E2>;
type F3 = (sth3: string) => Result<string, E3>;

//...Implementation

const result: Result<string, MyUnion> = f1('maybe').andThen(f2).andThen(f3)

with the proposed solution:

type F1 = (sth: unknown) => Result<string, MyUnion>;
type F2 = (sth2: string) => Result<string, MyUnion>;
type F3 = (sth3: string) => Result<string, MyUnion>;

//...Implementation

const result: Result<string, MyUnion> = f1('maybe').andThen(f2).andThen(f3)

I left out the dicrimininator but I think my argument still stands: In order to compose arbitrary functions returning Result types, one has to alter or overload their signatures. Thus reducing the expressiveness of the signature.

Additionally it is not possible to centrally handle Result types at the moment, because the error types of a given pipeline never line up.

I was drawn to this GREAT library, because it allows me to be expressive with error paths. At the same time, the possibility to easily compose different functions without them having to know the context in which they are composed would be a really BIG WIN. Especially, since the propsed changes by @paduc are minimal and non-breaking, I would be in favour of changing the interface.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Catching and handling different types of errors in promise chains
If second (and final) call returns successfully, we'll display a success message. Here's the main promise-chain:
Read more >
Error handling in long Promise chains | by Arthur Xavier
The handleError function returned a function which handled the error for that specific step on the Promise chain. It then would set a...
Read more >
How to handle error properly in Promise chain? - Stack Overflow
Yes, you want to handle all errors in the promise chain with a single catch. If you need to know which one failed,...
Read more >
Multiple error types - Rust By Example
In the following code, two instances of unwrap generate different error types. Vec::first returns an Option , while parse::<i32> returns a Result<i32, ...
Read more >
Error handling with promises - The Modern JavaScript Tutorial
Promise chains are great at error handling. When a promise rejects, the control jumps to the closest rejection handler. That's very convenient ...
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