Get return value of iterators when used in for-of loops

Currently, using a generator function that has a return value in a for-of loop means that we loose access to that return value.

In order to work around this, we need to explicitly manipulate the iterator, which can be annoying (e.g. we must not forget to call the iterator.return?.() function, which is done under the hood when using a for-of loop).

My proposal would be to allow retrieving the return value somehow. Here is an example of syntaxt that would allow this:

function* generate() {
  yield 1
  return "foo"
}

const returnValue = for (const item of generate()) {
  console.log(item) // 1
}

console.log(returnValue) // foo

You can achieve the same with:

function* generate() {
  yield 1
  return yield "foo"
}

for(const item of generate()) {
    console.log(item)
}

// 1
// foo

That isn't returning "foo". Its yielding "foo" then returning the result of that expression. That could be anything depending on who's calling next.

function* generate() {
  yield 1
  return yield "foo"
}

const gen = generate()
console.log(gen.next()) // { value: 1, done: false }
console.log(gen.next()) // { value: "foo", done: false }
console.log(gen.next("bar")) // { value: "bar", done: true }

One potential reason to not add new semantics to get the return value from iterators would be that the return value is not passed through when using the new iterator helper methods (proposal-iterator-helpers/issues/217) reducing the chance that iterators will have a useful return value.