Flow: Alternative type for generators

Created on 11 Oct 2016  路  7Comments  路  Source: facebook/flow

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>.

generators

Most helpful comment

this would help a lot in typing redux-saga https://github.com/redux-saga/redux-saga/issues/864#issuecomment-367820798

All 7 comments

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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sophiebits picture sophiebits  路  66Comments

vjpr picture vjpr  路  55Comments

danvk picture danvk  路  73Comments

jlongster picture jlongster  路  55Comments

gabro picture gabro  路  57Comments