-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
update bimap implementation to reject result of leftFn, and improve type signature #1
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is awesome man! thanks for that, specially the fact that bimap now maintains the state of the promise (as in rejected will remain rejected). As for changing from try/catch to then/catch it technically doesn't make any difference, so I'm fine if you want to change it but it's probably not worth much effort TBH.
src/async/bimap/bimap.js
Outdated
): Promise<T> { | ||
return p.then(rightFn, leftFn); | ||
): Promise<R> { | ||
return p.then(rightFn, (e: E): Promise<R> => Promise.reject(leftFn(e))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey man, the type here is wrong... it should be (e: E): Promise<any> => ...
since the leftFn is (E) => any. Which I should fix to be honest because we should not be using weak types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wasn't sure what to do here. I still half-feel this is correct.
If we were to write out the rightFn
it would look like this
function bimap<T, R, E>(
leftFn: (E) => any,
rightFn: (T) => R,
p: Promise<T>
): Promise<R> {
return p.then(
**(v: T): Promise<R> => Promise.resolve(rightFn(v)),**
(e: E): Promise<R> => Promise.reject(leftFn(e)),
);
}
Since rightFn returns Promise<R>
, shouldn't leftFn return Promise<R>
too – so that the function on both sides returns the same type?
(If leftFn returned Promise<any>
, would bimap then return Promise<any>
?)
In reality, once the promise is failed, it won't contain an R
anymore, and of course we can't annotate the type of the rejected state value
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh I see the confusion. So promises only annotate the Success value, not the error. So as long as the promise on the left is rejected we cannot type it.
facebook/flow#1232
facebook/flow#5042
Alternatively we could say, incorrectly, Promise<R | SomeErrorType> but that's just us being super clever :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah that's my understanding. Which is a huge caveat of this approach, but I still think there's a lot of benefits to it which is why I'm PRing :).
Unfortunately that union trick won't work for long:
As a comment to the issues around being unable to type the rejection because anything might be thrown, as long as every Promise has a catch((err: any) => ConcreteErrVal)
defined, shouldn't it then be possible to type the resulting Promises' rejected side with that Promise<SuccessType, ConcreteErrVal>
. (And prior to that catch, it would have to be Promise<SuccessVal, any>
?)
Getting off topic... how should we resolve the bimap?
src/async/bimap/bimap.spec.js
Outdated
@@ -3,27 +3,37 @@ | |||
import bimap from './bimap'; | |||
|
|||
describe('async/bimap', () => { | |||
test('should only call left fn if promise rejects', async (): Promise<any> => { | |||
const leftFn: Function = jest.fn(); | |||
test('should only call leftFn if promise rejects', async (done: Function): Promise<any> => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you're going to change from try/catch to .then/catch the can you remove the async keywords?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will do
cfab316
to
199ff94
Compare
Sorry dude, I'll merge it now as it makes sense enough and I honestly don't know the answer, but I think it makes sense (until we can type Errors in Promises). |
Updated the return type to be Promise, as it doesn't have to be the same type as the original promise.
I updated the test as it didn't look quite right – I think this method (.then, .catch rather than try/catch block) feels a bit more robust. I will update other tests to use this as well (and have similar updates for type signatures) if you're happy with it.
Some additional updates happened to index files as a result of running
build