feat(andFinally): add andFinallyFunctionality#536
feat(andFinally): add andFinallyFunctionality#536kishore03109 wants to merge 1 commit intosupermacro:masterfrom
Conversation
| return new ResultAsync( | ||
| this._promise.then((res) => { | ||
| if (res.isErr()) { | ||
| return f(res.error) |
There was a problem hiding this comment.
I'd have a few questions here:
- Doesn't this imply that f should be typed as
f: (t: T | E) => R? (since you're calling it with res.error) - Is there a reason we need
newValue instanceof ResultAsync ? newValue._promise : newValuein the ok branch but not in theisErr()branch? - Why even unbox the type instead of just passing the Result object to f? The union type seems unergonomic and erases whether an error occurred or not.
braxtonhall
left a comment
There was a problem hiding this comment.
Nice! I think it might be even nicer though if the original values are not lost when calling .andFinally
As a user, I think I expect that finally used for side effects, and probably shouldn't change the type of the result.
For example with promises (linked in your PR description):
(async () => {
const resolveFinally = await Promise.resolve("foo")
.then((a) => a)
.finally(() => "bar");
const rejectFinally = await Promise.reject("foo")
.catch((a) => a)
.finally(() => "bar");
console.log(resolveFinally, rejectFinally); // prints '"foo" "foo"'
})();I guess the try/finally in JavaScript is a counter-example, because the finally block can overwrite the return in the try or catch block, but in the case of no return statement in the finally block, the original return value in the try or catch block is used.
It would be nice to be able to still observe that an error occurred even after the andFinally callback executes. Here's an example that looks just like JavaScript promises:
const doStuff: Result<string, number> = ok('start db connection')
.andThen(() => {
// do stuff that might return an err()
const result: Result<string, string> = ok('do something')
return result
})
.andFinally(() => {
// close the db connection
})
.orElse(() => {
// trigger some alarm!
return err(1);
})... although this just looks suspiciously like #456
|
Closing because some of the comments made by @macksal & @braxtonhall were valid, and was not construct a neat way to address their concerns |
|
Hi @kishore03109 I've added a new implementation in #588 with a slightly different design, please consider reviewing if you find it useful! |
Description
Add 'finally' functionality to neverthrow. Overall leads to clearer typing with less verbose code. The mental model is similar to the native finally.
This PR attempts to solve 2 main issues. Consider the example below:
Notice the return type of the
safeFunctionis typed to an unintuitive type. Not sure if there was a convenient way for error recovery while mutating theOktype. WithandFinally, there is easier control over theOktype during error recovery as such:Additionally, this solves #525. As documented in the issue, the below code becomes less verbose.
Before
After
Testing
Have added some minimal tests to capture correct behaviour.