Reputation: 973
Consider the following iterator. It yields strings 'foo' and 'bar' and then returns 'quux' as a return value. I can use Array.from
to extract the yields from the iterator but if I do this, I have no way of reading out the return value. The return value is no longer returned by the iterator since Array.from
already received (and discarded?) it as part of the protocol.
const iterator = (function* () {
yield 'foo'
yield 'bar'
return 'quux'
})()
const [foo, bar] = Array.from(iterator)
const quux = // ???
The only solution I can think of is writing a spy procedure that monitors the iteration and stores the return value into a predefined variable as a side effect before Array.from
discards the return value. Are there better alternative ways of accessing the return value?
let quux
const spy = function* (i) { /* extract return value from i and store it to quux */ }
const [foo, bar] = Array.from(spy(iterator))
Upvotes: 5
Views: 1177
Reputation: 985
Another solution:
function extractIterator<TItem, TResult>(iter: Generator<TItem, TResult>) {
const items: TItem[] = [];
let result: IteratorResult<TItem, TResult>;
while ((result = iter.next())) {
if (result.done) {
return {
items,
result: result.value,
};
}
items.push(result.value);
}
throw 'unreachable';
}
Upvotes: -1
Reputation: 29012
You are right - when the iterator next
function returns { done: true, value: 'whatever' }
the value is silently discarded.
As you already said, you could write a wrapper function (or a class, if you wanted to). But instead of saving it to an external variable, you could make it convert this last value to a regular iterated value.
For example:
function* yieldFinal (iterator) {
let done, value
do {
({ done, value } = iterator.next())
yield value
} while (!done)
}
const iterator = (function* () {
yield 'foo'
yield 'bar'
return 'quux'
})()
const [foo, bar, quux] = Array.from(yieldFinal(iterator))
console.log(foo, bar, quux)
(Note: If there was no explicit return value, then you'd get undefined
for the last value.)
But, then the question is, why do you even need to go to these lengths? Instead of writing return 'quux'
you could write yield 'quux'; return
and achieve the same thing without going through all the hoops...
Upvotes: 3