Currently, Flow has Generator type that can be used to declare static type of a generator in terms of Yield, Return and Next. This model is sound and allows to type-check both generator functions and code that interacts with generator objects.
Unfortunately, a whole range of techniques that require Next to be a function of Yield are not possible with this model:
function * coroutine () {
const num = yield getNumber(); // returns Promise<number>
const str = yield getString(); // return Promise<string>
}
In the above example there is no way to define Generator type so that num is a number and str is a string.
My proposal is to add a special type for this case: FnGenerator<Fn, Return>. Return has the same meaning, while Fn is a type of polymorphic function that. For the above example Fn could be defined like this <T>(p: Promise<T>) => T.
Enforcing this behaviour from the outside would be very hard (if not impossible), so it's probably easier to leave this part unsound. For example, it could be equivalent to Generator<any, Return, any>.
Here's another approach: You can add a wrapper generator with the sole purpose to annotate the return type of yield. This generator is called via yield *
// Example 1: returns the promise return type
function * promisedGen<R> (promise: Promise<R>) : Generator<*, R, *> {
return yield promise
}
// Example 2: returns the yielded type
function * idGen<R> (val: R) : Generator<*, R, *> {
return yield val
}
function * coroutine () {
const num = yield * promisedGen(getNumber())
const str = yield * promisedGen(getString())
const num2 = yield * idGen(123)
}
This works nicely for me. It would be interesting to find a way to ensure the correct usage of such helper-generators for the caller of coroutine().
I have another use-case for this, in an experimental parser I'm developing. Similarly to how the original poster wants yielding a Promise<R> to return an R, I want yielding a value of type Either<L,R> to return an R, with the caller of the coroutine doing error handling.
This would also be helpful for libraries like redux-saga.
Any update on this?
this would help a lot in typing redux-saga https://github.com/redux-saga/redux-saga/issues/864#issuecomment-367820798
Is this on the roadmap somewhere or just an idea ?
FYI, the PR above solves the issue pretty well I would say (https://github.com/keybase/client/pull/14948/files#diff-518e3f63aab2dd78e7f9df3ebeceeed0).
It means you can yield* callPromise() and the types will be correctly applied. I'm not aware of any downsides so far.
Most helpful comment
this would help a lot in typing redux-saga https://github.com/redux-saga/redux-saga/issues/864#issuecomment-367820798