-
Notifications
You must be signed in to change notification settings - Fork 12.6k
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
TypeScript 2.0 change in IterableResult<T> makes implementing iterators harder #11375
Comments
This does seem to be a bug and a divergence from IteratorResult in the ECMAScript spec. The spec states the following about the
|
There is a long chain of issues around this. It is a little confusing. See #8357 for some the motivation. |
Both #8357 and #8938 mention that with boolean literal types, We now have boolean literal types, but it seems it's still difficult to fix - see #2983 (comment). TL;DR the fix for this is now held up on default generic type variables (#2175). Unless of course someone can come up with a better alternative. |
To me the fix seems easy: switch the definition in
Entangling this with an enhancement that tries to enforce complex conditions for the property's optional status seems overreaching. I don't see why it should be held up on default generic type variables. |
|
@yortus I've just wrote an alternative #2983 (comment) |
Thanks @yortus . It seems to me like it's not the previous definition of If I understand the background on #8357, that would only only comes about when using strict null checking. The change in |
@BurtHarris the problem in both the current and the previous function* foo() {
yield 1;
yield 2;
yield 3;
return 'done';
}
// Looping over the next() values for foo() gives:
// { done: false, value: 1 }
// { done: false, value: 2 }
// { done: false, value: 3 }
// { done: true, value: 'done' } So the type of |
Yes, but the latest issue you raise sounds like a problem with generators, not necessarily a problem with iterators. And it certainly makes sense to me that the type associated with a generator could perhaps need to account for the difference between yield and return. However, the code I'm working toward isn't (and probably won't be) dependent on generators. Now I'll be the first to admit I'm not an expert on generators or iterators, and that if I were designing these features I would have specified the protocol differently. But based on my reading of the iterator protocol from Mozilla.org, I inferred that in the value returned from a But in terms of a practicing programmer (using a released tool) rather than a language designer, I would prefer that TypeScript 2 accept the old interface until the details of proper enforcement the evolved protocol can be worked out, or until I opt-in to enforcement of a more restrictive one. |
This work is based on changes by @BurtHarris in #26.
I agree with @BurtHarris that the interface |
I have code creating and using an iterator directly and just had to fix a bug that would've been caught if a the type definition for |
I was about to report this as a bug myself, does anyone know what's happening? |
@rbuckton can you try changing this to a union return type and validate that it improves RWC / the examples listed here? |
Currently waiting on DefinitelyTyped infrastructure changes. |
@DanielRosenwasser What exact change is being waited? Could you please give the link to DT issue for tracking? |
Not sure if this has been suggested but could we fix this by just defining type IteratorResult<T> =
| { done: false, value: T }
| { done: true, value?: T }; |
edit: see my later comment |
No, that’s not correct: function* g() {
yield 812;
return 1208;
}
const iter = g();
console.log(iter.next()); // { done: false, value: 812 }
console.log(iter.next()); // { done: true, value: 1208 } |
Ah, of course, hahaha It kind of has to be two types though, the return value doesn't have to be the same as the yielded value: function* g() {
yield 1
yield 2
return 'hello'
}
const iter = g()
console.log(iter.next()); // { done: false, value: 1 }
console.log(iter.next()); // { done: false, value: 2 }
console.log(iter.next()); // { done: true, value: 'hello' } type IteratorResult<T, R> =
| { done: false, value: T }
| { done: true, value: R }; relevant: #2983 |
For this particular use case, I think union type should suffice. const a: IteratorResult<number | string> = iter.next() |
Using a type union wouldn't accurately let me work with the iterator though: function* g() {
yield 1
yield 2
return 'hello'
}
const iter: Iterator<number | string> = g()
for (let num of iter) {
console.log(num * 2) // <- cannot multiply string with 2
} This will incorrectly tell me that |
This should be resolved by #30790 |
It turns out #30790 does pretty much exactly what I suggested (plus more!). Nice. 😃 |
Why close this? #30790 is a PR, not an issue, and it hasn't been merged yet. |
Agreed. @BurtHarris can you reopen this? |
Should be merged now. |
Thank you all. |
TypeScript Version: 2.0.3
The definition in
lib.es6.d.ts
ofIteratorResult
(removing the?
aftervalue
) seems to have broken existing Iterator implementations, and is particularly troublesome with strict null checking enabled. See http://stackoverflow.com/questions/39813087/why-did-typescript-2-0-change-iteratorresultk for more details.Code
A short version:
this version works
original bug
Expected behavior:
Clean compile under TypeScript 2.0
Actual behavior:
Errors reported: TS2322: Type '{ done: true; }' is not assignable to type 'IteratorResult'. Property 'value' is missing in type '{ done: true; }'
Note: with strict null checking on, I seem to need to go further, resorting to
The text was updated successfully, but these errors were encountered: