Uh oh!
There was an error while loading. Please reload this page.
add types for iterator helpers proposal - #58222
Conversation
Bruce Pascoe (fatcerberus)
commented
Apr 17, 2024
The DOM typings are maintained at https://github.com/microsoft/TypeScript-DOM-lib-generator |
Kevin Gibbons (bakkot)
commented
Apr 17, 2024
More concretely, I'll need someone to tell me how to handle the change: changing the DOM typings to use |
Would the following work?
This would allow what you're looking for: keeps compatibility for pre-esnext targets, while allowing the helper methods to be merged into Sparse illustration: // @target: esnext// @lib: esnext// @filename: lib.es2015.iterable.d.tsinterfaceIterator<T,TReturn=any,TNext=undefined>{next(...args: []|[TNext]): IteratorResult<T,TReturn>;return?(value?: TReturn): IteratorResult<T,TReturn>;throw?(e?: any): IteratorResult<T,TReturn>;}interfaceIterable<T>{[Symbol.iterator](): Iterator<T>;}interfaceIterableIterator<T>extendsIterator<T>{[Symbol.iterator](): IterableIterator<T>;}interfaceNativeIterator<T,TReturn=void,TNext=undefined>extendsIterator<T,TReturn,TNext>{[Symbol.iterator](): NativeIterator<T,TReturn,TNext>;}interfaceGenerator<T=unknown,TReturn=any,TNext=unknown>extendsNativeIterator<T,TReturn,TNext>{// etc.}interfaceArray<T>/* etc. */{// was: [Symbol.iterator](): IterableIterator<T>;[Symbol.iterator](): NativeIterator<T>;// was: entries(): IterableIterator<[number, T]>;entries(): NativeIterator<[number,T]>;// etc.}// @filename: lib.esnext.iterator.d.tsinterfaceNativeIterator<T,TReturn,TNext>{map<U>(callbackfn: (value: T,index: number)=>U): NativeIterator<U>;// etc.}// @filename: test.tsconstmappedArrayIterator=['a','b','c'].entries().map(([k,s])=>k*s.charCodeAt(0));// NativeIterator<number>constcastToIterableIterator: IterableIterator<number>=mappedArrayIterator;// NativeIterator<T> remains assignable to IterableIterator<T>, for what it's worthAs for the question of extending |
Kevin Gibbons (bakkot)
commented
Apr 17, 2024
Nice, that sounds like a good approach to me. |
Kevin Gibbons (@bakkot) the approach I am experimenting with to support // lib.esnext.iterator.d.ts/// <reference lib="es2015.iterable" />export{};// Abstract type that allows us to mark `next` as `abstract`declareabstractclassIterator<T>{abstractnext(value?: undefined): IteratorResult<T,void>;}// Merge all members of `NativeIterator<T>` into `Iterator<T>`interfaceIterator<T>extendsglobalThis.NativeIterator<T,void,undefined>{}// Capture the `Iterator` constructor in a type we can use in the `extends` clause of `IteratorConstructor`.typeNativeIteratorConstructor=typeofIterator;declare global {// Global `NativeIterator<T>` interface that can be augmented by polyfillsinterfaceNativeIterator<T,TReturn,TNext>{// prototype elements}// Global `IteratorConstructor` interface that can be augmented by polyfillsinterfaceIteratorConstructorextendsNativeIteratorConstructor{// static elements}varIterator: IteratorConstructor;}// lib.es2015.iterable.d.ts
...
interfaceNativeIterator<T,TReturn=void,TNext=undefined>extendsIterator<T,TReturn,TNext>{[Symbol.iterator](): NativeIterator<T>;}
...And in use: newIterator<number>();// ts(2511): Cannot create an instance of an abstract class.classCextendsIterator<number>{}// ts(2515): Non-abstract class 'C' does not implement inherited// abstract member next from class 'Iterator<number>'.Lib references can't really be referenced as modules, and even if you could this provides no exports. However, we will still augment the global scope with the types defined in |
Ron Buckton (rbuckton)
commented
Apr 17, 2024
There need to be a few other changes so that it can also be used with generators, though. |
| find<S extends T>(predicate: (value: T, index: number) => value is S): S | undefined; | ||
| find(predicate: (value: T, index: number) => unknown): T | undefined; | ||
| readonly [Symbol.toStringTag]: "Iterator"; |
There was a problem hiding this comment.
I would suggest defining this as
| readonly[Symbol.toStringTag]: "Iterator"; | |
| readonly[Symbol.toStringTag]: string; |
otherwise subclasses of Iterator won't be able to redefine it.
| declare var Iterator: (abstract new <T>() => NativeIterator<T>) & IteratorConstructor; | ||
| // TODO BEFORE MERGING: update all existing IterableIterator-return methods to return NativeIterator |
There was a problem hiding this comment.
As suggested elsewhere, I would suggest you define NativeIterator as follows in the es2015 libs and then just update all of the IterableIterator references to NativeIterator:
interfaceNativeIterator<T,TReturn=void,TNext=undefined>extendsIterator<T,TReturn,TNext>{[Symbol.iterator](): NativeIterator<T,TReturn,TNext>;}There was a problem hiding this comment.
Should I split that into a separate PR, or do it here?
| @@ -0,0 +1,133 @@ | |||
| interface NativeIterator<T, TReturn = void, TNext = undefined> extends Iterator<T, TReturn, TNext> { | |||
There was a problem hiding this comment.
The export {} trick mentioned in my earlier comment can address the abstract next() method definition.
| @@ -0,0 +1,133 @@ | |||
| interface NativeIterator<T, TReturn = void, TNext = undefined> extends Iterator<T, TReturn, TNext> { | |||
There was a problem hiding this comment.
The word choose "Native" is not so good. Do we have other options?
There was a problem hiding this comment.
Ron Buckton (@rbuckton) had previously suggested Builtin, which I'm also fine with.
Ron Buckton (@rbuckton) does the interface merging make any existing "custom" Iterator objects fail type validation in target:esnext, since they won't implement the new Iterator.prototype methods? Edit: I overlooked the module hacking. Very nice. |
Jack Works (Jack-Works)
commented
Apr 17, 2024
It does not merging the current Iterator interface, but create a new one called NativeIterator |
Ron Buckton (rbuckton)
commented
Apr 17, 2024
Kevin Gibbons (@bakkot) is correct. This should not affect anyone implementing a custom After this is in we may want to add a shortcuts for it to |
This reverts commit bd51b00. (and subsequent commits)
Kevin Gibbons (bakkot)
commented
Apr 18, 2024
Updated almost exactly following this comment, except that I had BuiltinIterator's A consequence of this change is that the type of Also, passing declareabstractclassIterator<T>{abstractnext(value?: undefined): IteratorResult<T,void>;}means that classes attempted to implement I have test cases illustrating the difficulties: I see a few approaches to improving this last issue:
|
Kevin Gibbons (bakkot)
commented
Apr 18, 2024
One detail not captured by the types here is that the iterator returned by helpers like |
Ron Buckton (rbuckton)
commented
Apr 18, 2024
We could probably add |
Ron Buckton (rbuckton)
commented
Apr 19, 2024
Do helpers like |
Ron Buckton (rbuckton)
commented
Apr 19, 2024
Regarding the typing issues, I'm hoping #58243 might help with that. |
Kevin Gibbons (bakkot)
commented
Apr 19, 2024
Nope, just Suggestions for the name? |
Ron Buckton (rbuckton)
commented
Apr 19, 2024
I suppose that's fine. Daniel Rosenwasser (@DanielRosenwasser), do you have any thoughts on the name for this type? |
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Ron Buckton (rbuckton)
commented
Jul 19, 2024
I've made updates to align with the changes in #58243, though it required a few small compromises. If necessary, we can refine this somewhat after its in the beta. |
TypeScript Bot (typescript-bot)
commented
Jul 19, 2024
The TypeScript team hasn't accepted the linked issue #54481. If you can get it accepted, this PR will have a better chance of being reviewed. |
Ron Buckton (rbuckton)
commented
Jul 19, 2024
I realize I neglected to run the user test suite before merging, though I expect it will only call out projects that were already called out by #58243. Running that suite now in case that assumption turns out to be false. TypeScript Bot (@typescript-bot) run dt |
Ron Buckton (rbuckton)
commented
Jul 19, 2024
Also running benchmarks as I expect I need to put up a follow-up PR that adds a TypeScript Bot (@typescript-bot) perf test |
Starting jobs; this comment will be updated as builds start and complete.
|
Kenta Moriuchi (petamoriken)
commented
Jul 21, 2024
Why |
Kenta Moriuchi (petamoriken)
commented
Jul 22, 2024
ref: #59388 |
Fixes#54481.
I have only minimal tests because almost all the types are copied directly from Array with very minimal changes (mostly dropping the third "array" parameter to callbacks and the "thisArg" parameter to callback-taking methods, and returning
NativeIterator<T>instead ofT[]). But I'm happy to make the tests more extensive if you'd like.For reviewing:
BuiltinIteratorandAsyncBuiltinIteratortypes and adopt them everywhere except the.generatedfiles.AsyncBuiltinIteratorisn't necessary yet but I figured we might as well do this plumbing work now.The "rebaseline" commits are just running
npm run test -- --no-lint; npx hereby baseline-acceptand committing the result.Current status (as of 2024-04-25):
CloseableBuiltinIteratoror something to mean "built-in iterator with areturnmethod"I'll address the outstanding todos one #58243 lands.