-
Notifications
You must be signed in to change notification settings - Fork 12.8k
IteratorResult<T> definition conflicts with the JS spec #38479
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Suggested fix won't work as described here https://github.com/microsoft/TypeScript/pull/30790/files#r282595851 |
I confess I don't fully understand what the feared failure is, based on reading issue 30790. Is there a specific example of a type deduction failure that can illustrate that? In any case, an alternative fix could be as follows, although without fully understanding the objection, I don't know if this is any better. This would see IteratorReturnResult tun into a type alias, and default TResult to match T to improve type inference: type IteratorReturnResult<TResult> = { done: true, value?: TResult } | { done?: false, value: TResult }
type IteratorResult<T, TReturn = T> = IteratorYieldResult<T> | IteratorReturnResult<TReturn> |
I think there 2 kind of propblems will arise with
const list = ['v1', 'v2', 'v3']
const f: () => Iterator<string, number> = () => {
let index = 0
return {
next: (): IteratorResult<string, number> => {
console.log(list)
if (index < list.length) {
return { value: list[index++]}
} else {
return { done: true, value: index } // Ooops, I can forget to return value here
}
}
}
}
const iter = f();
const res = iter.next();
if (res.done) {
console.log(`I wish I had ${res.value * 10} values instead`);
// ~~~~~~~~~ Object is possibly 'undefined'. ts(2532)
} |
Both points are inconveniences, but this is what the spec requires - |
One potential solution would be to define type IteratorResult<T> =
| { done: false, value: T }
| { done: true, value?: T }; Although it’s not clear what to do in the case where |
The only time it would be type-safe to allow @DanielRosenwasser - Any thoughts on extending the same treatment of a |
@rbuckton Maybe I'm missing something but the discriminated union I described would have const iter = obj[Symbol.iterator]();
while (!iter.done) {
iter.value; // never undefined, no need to check
} No need to check for undefined inside the loop since the discriminated union in combination with CFA takes care of that. The only time you'd need to check is if edit: I screwed up the loop, but it gets the point across and I'm too lazy to fix it. 😛 |
To reiterate, the problem is that, as written,
|
I agree that
We made it such that calling |
fwiw I ran into this in practice when attempting to use a
|
Since, I, too, am having compilation problems regarding the IteratorReturnResult I add to this issue by adding a point in favor of @ldantonov. The following is the current definition of the interface IteratorYieldResult<TYield> {
done?: false;
value: TYield;
}
interface IteratorReturnResult<TReturn> {
done: true;
value: TReturn; // here the value can't be undefined
}
type IteratorResult<T, TReturn = any> = IteratorYieldResult<T> | IteratorReturnResult<TReturn>;
interface Iterator<T, TReturn = any, TNext = undefined> {
next(...args: [] | [TNext]): IteratorResult<T, TReturn>;
return?(value?: TReturn): IteratorResult<T, TReturn>; // here the value provided by the user can be undefined
throw?(e?: any): IteratorResult<T, TReturn>;
} If i try to implement the class class MyIterator<T, TReturn, TN> implements Iterator<T, TReturn, TN> {
next(...args: [] | [TN]): IteratorResult<T, TReturn> {
throw new Error("Method not implemented.");
}
return?(value?: TReturn): IteratorResult<T, TReturn> {
return { done: true, value };
// what should I use as value if the user set the value parameter to undefined by calling myIterator.return() with empty paranthesis?
// from MDN https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterator_protocol
/*
return(value) Optional
A function that accepts zero or one argument and returns an object conforming to the IteratorResult interface,
typically with value equal to the value passed in and done equal to true.
Calling this method tells the iterator that the caller does not intend to make any more next() calls and can perform any cleanup actions.
*/
}
throw?(e?: any): IteratorResult<T, TReturn> {
throw new Error("Method not implemented.");
}
} I get the following error:
So why the As they are right now the I don't know what is the best solution but i upvote the one proposed by @ldantonov since is the most closed to the iterator protocol: the iterator protocol itself tells you to check for undefined values |
The shape for We previously investigated whether we could make properties optional if they are instantiated with the type For now, I am closing this as a design limitation. |
TypeScript Version: 3.8.3
Search Terms: iterator return type
Code
Expected behavior:
The code should compile without errors.
Actual behavior:
The code compiles with the error: "Type '{ done: true; }' is not assignable to type 'IteratorResult<string, any>'.
Property 'value' is missing in type '{ done: true; }' but required in type 'IteratorReturnResult'.(2322)"
The error can be bypassed by changing { done: true } to { value: undefined, done: true }. However, the specification allows omitting the value property. See Iteration Protocols
A suggested fix would be to change the definition of the type IteratorReturnResult to:
Playground Link: https://www.typescriptlang.org/play?#code/MYewdgzgLgBANgS2jAvDA2gcgG4EZMA0MOATIcdgMyYC6AUHaJLAGYBcMAFAJSoB8MAJJQApgCcAhlBBiAPNDEIwAcwFoe-GAG86MeCNhKAJiIAeqGAAZdMMQYCuYsNpt6wZqBx4dh4qTIAlEQh7OCh5KEUVNQEdPXiYJggQOBEAOjgQZU5EaG5XeIQWLmMzGFl4JCgMkRUoAAteOIT4uyhHZy0YbAk4exEOXKh0UtMAajGaAF8CvSmYETgIERcW1ocnbRgjcAGYSP6YGbXj+NOZqaA
Related Issues:
#29982
The text was updated successfully, but these errors were encountered: