Reputation: 10912
I'm trying to define a zip function in javascript with flow types added to it.
The types I have for now are the following:
export function *zip<T>(...iterables:Array<Iterable<T>>): Iterable<Array<T>> {
const iterators = iterables.map(iterable => iter(iterable));
while(true){
const items = iterators.map(iterator => iterator.next());
if (items.some(item => item.done)){
return;
}
yield items.map(item => item.value);
}
}
function *iter<T>(iterable:Iterable<T>): Iterator<T> {
yield* iterable;
}
The error flow (0.64) gives me is on the return;
line and it says:
Generator
This type is incompatible with the expected return type of
$Iterable: tools/misc.js:182
Property `@@iterator` is incompatible:
function type: /private/tmp/flow/flowlib_38c3acbb/core.js:508
This type is incompatible with
function type: /private/tmp/flow/flowlib_38c3acbb/core.js:503
The example in flow's documentation looks very similar so I'm not sure what's wrong here.
Any suggestion concerning the types (or even the code itself) is also welcome.
Edit The error on flow version 0.92.1 is:
Cannot return undefined because undefined is incompatible with
T
in array element of type argumentYield
of the return value of property@@iterator
.
Upvotes: 1
Views: 2007
Reputation: 1235
Based on zip generator return type, it is expected to yield values of type Array<T>
.
However, yield items.map(item => item.value);
produces Array<void | T>
, since each item
in that map callback is IteratorResult<T, void>
. So there's a type mismatch between actual and expected yield value.
That being said, you are already checking your items with:
if (items.some(item => item.done)){
return;
}
, so by the time execution reaches yield
none of the item values can be undefined
. Unfortunately Flow can't figure it out on its own. But we can force it into type casting that value:
export function *zip<T>(...iterables:Array<Iterable<T>>): Iterable<Array<T>> {
const iterators = iterables.map(iterable => iter(iterable));
while(true){
const items = iterators.map(iterator => iterator.next());
if (items.some(item => item.done)){
return;
}
yield ((items.map(item => { return item.value }): Array<any>): Array<T>);
}
}
Upvotes: 2