TypeScript
TypeScript copied to clipboard
Iterators/Generators, next(), and unsafe yield statement types
Acknowledgement
- [X] I acknowledge that issues using this template may be closed without further explanation at the maintainer's discretion.
Comment
🔎 Search Terms
iterator generator yield next
🕗 Version & Regression Information
Current behaviour has existed since 3.6.0.
With upcoming changes to iterators, I wonder whether it might be worth quickly revisiting the behaviour of the next()
iterator method.
As discussed at #30790, when interacting with iterators manually, the compiler will always consider it valid if next()
is called with zero-arity, even if TNext
is of a type that cannot be void/undefined. The rationale for allowing this is that any parameter passed to the first call to next()
gets thrown away, so it should be valid to allow the parameter to be absent.
This does have some type safety implications as originally discussed, but this also causes a related problem with the type of the yield
statement in generators, which I don't think has ever been raised before:
function *g(): Generator<null, string, number> {
const a = yield null; // const a: number
return a.toString(16);
}
const it = g();
it.next();
it.next(); // TypeError: a is undefined
The function signature of next()
allows the second call to be made without a parameter, but the compiler assumes that the type of the yield
statement will always be TNext
, and never be undefined. Although it violates the semantic intention of the generator signature, it seems like yield
potentially returning undefined is a forced possibility if next()
always allows calls with zero parameters, which was discussed previously and considered necessary.
Even if there's no alternative way to define next()
, I wonder if the question of how to handle yield
specifically needs considering.
related: #58243