The following code does not pass flow check.
// @flow
/* global describe, it */
const Promise = require('bluebird')
describe('Flow', () => {
it('should work for async/await pattern.', async () => {
const value:number = await Promise.resolve(10)
console.log(value)
})
})
And here's how flow complains.
test/flow.spec.js:7
7: const value:number = await Promise.resolve(10)
^^^^^^^^^^^^^^^^^^^ call of method `resolve`
7: const value:number = await Promise.resolve(10)
^^^^^^^^^^^^^^^^^^^ Bluebird$Promise. This type is incompatible with
522: declare function $await<T>(p: Promise<T> | T): T;
^^^^^^^^^^^^^^ union: type application of identifier `Promise` | type parameter `T` of await. See lib: /private/tmp/flow/flowlib_d8b774b/core.js:522
Member 1:
522: declare function $await<T>(p: Promise<T> | T): T;
^^^^^^^^^^ type application of identifier `Promise`. See lib: /private/tmp/flow/flowlib_d8b774b/core.js:522
Error:
7: const value:number = await Promise.resolve(10)
^^^^^^^^^^^^^^^^^^^ Bluebird$Promise. This type is incompatible with
522: declare function $await<T>(p: Promise<T> | T): T;
^^^^^^^^^^ Promise. See lib: /private/tmp/flow/flowlib_d8b774b/core.js:522
Member 2:
7: const value:number = await Promise.resolve(10)
^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` of await
Error:
7: const value:number = await Promise.resolve(10)
^^^^^^^^^^^^^^^^^^^^^^^^^ Bluebird$Promise. This type is incompatible with
7: const value:number = await Promise.resolve(10)
^^^^^^ number
Problem here seems like await expects native Promise type, not Bluebird$Promise. How can I use Bluebird$Promise instead of native Promise?
I'm using bluebird interface file with this one.
According to this comment there isn't way to do this yet. In that case I just want to raise this issue.
Possible workaround for this would be to: (1) redeclare $await (https://github.com/facebook/flow/blob/master/lib/core.js#L522) in a [lib] file, using an import of 'bluebird' Promise, but importing in lib files is not supported; or (2) https://github.com/facebook/flow/issues/1635#issuecomment-208512377
Should the definition of await be using the $Shape of Promise instead of a Promise declaration itself?
It seems that according to spec the only thing that is required is then method
Actually it doesn't even require a then method. The engine always coerces the awaited expression into a promise automatically, so you are allowed to await a value that may or may not be a promise.
The spec defines how await desugars. The internal desugared logic for each awaited expression is: take the expression to the right of await, wrap it in Promise.resolve(...), and then wait for the fulfilment value of _that_ promise.
So these are both totally valid (and are functionally identical):
await Promise.resolve('foo');
await 'foo';
Here is a live example using Babel's desugaring, which follows the spec correctly.
Why would you ever want to await a non-thenable value... Possible reasons:
Admittedly these aren't everyday use cases, but they are valid according to the spec, so it would be wrong for Flow to type-check awaited values as thenables.
In conclusion... Flow should allow any value to follow the await keyword, even null/undefined. (The only thing you can say for sure about typing is: the evaluated result of the entire (await X) expression is guaranteed _not_ to be a thenable.)
so it would be wrong for Flow to type-check awaited values as thenables.
No one says that await-ing non-thenable is an error, it's just what's required for a value to be unwrapped.
No one says that await-ing non-thenable is an error, it's just what's required for a value to be unwrapped.
Not sure I follow. Can you elaborate? AFAICT, flow's core.js declares that await requires a thenable. Or am I misunderstanding?
No, it currently requires it to be an instance of global Promise, so it won't work with Bluebird or other libs. This PR fixes that: https://github.com/facebook/flow/pull/2291
Sorry, I meant promise. Anyway... it looks like your PR just changes await to also accept Thenable as well as Promise. But my point was it can be any value at all, even primitives or null/undefined. For example, await 123 is valid. With your PR, doesn't it still fail code like await 123?
With your PR, doesn't it still fail code like await 123?
It doesn't, and it doesn't fail now
OK looks like I misunderstood the error message
Possible workaround for this would be to: (1) redeclare $await (https://github.com/facebook/flow/blob/master/lib/core.js#L522) in a [lib] file, using an import of 'bluebird' Promise, but importing in lib files is not supported; or (2) #1635 (comment)
I've had declare function $await<T>(p: BluebirdPromise<T> | T): T; work just fine in the definition file I'm using for Bluebird.
For me the clearest workaround is to override global Promise in app entry point:
global.Promise = require('bluebird')
And then if you need bluebird specific methods I will import bluebird again :
import Bluebird from 'bluebird'
async function main () {
Bluebird.delay(100)
}
@barczaG It won't really work, though, because Flow won't see result of Bluebird.delay(100) as Promise
The problem here is that an async function needs to be able to await any "thenable". Here is an example of what should be accepted by flow:
/* @flow */
const thenable = { then: (cb) => cb('thenable') }
async function foo () {
const a: string = await Promise.resolve('a')
const b: string = await Promise.resolve(thenable)
const c: string = await thenable
return a + b + c
}
Here's a basic "thenable" being awaited inside an async function on node 7 with the --harmony-async-await flag:

Hey! What's the status of this?
There was a PR fixing this: https://github.com/facebook/flow/pull/2291 — but it seems to have been reverted without explanation, and I can't find any info about the reasons why.
This is blocking me because I want to provide a thenable class in a _library_ — so I can't use the workaround of overriding $await, since it's something all users of the library would have to do.
I can send a PR again, but will be easier if I understand why the original one was rejected.
/cc @mroch @bhosmer
Most helpful comment
The problem here is that an
asyncfunction needs to be able toawaitany "thenable". Here is an example of what should be accepted by flow:Here's a basic "thenable" being
awaited inside anasyncfunction on node 7 with the--harmony-async-awaitflag: