Skip to content
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

add types for iterator helpers proposal #58222

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions src/compiler/commandLineParser.ts
Expand Up @@ -236,6 +236,7 @@ const libEntries: [string, string][] = [
["esnext.object", "lib.esnext.object.d.ts"],
["esnext.array", "lib.esnext.array.d.ts"],
["esnext.regexp", "lib.esnext.regexp.d.ts"],
["esnext.iterator", "lib.esnext.iterator.d.ts"],
["decorators", "lib.decorators.d.ts"],
["decorators.legacy", "lib.decorators.legacy.d.ts"],
];
Expand Down
1 change: 1 addition & 0 deletions src/lib/esnext.d.ts
Expand Up @@ -7,3 +7,4 @@
/// <reference lib="esnext.collection" />
/// <reference lib="esnext.array" />
/// <reference lib="esnext.regexp" />
/// <reference lib="esnext.iterator" />
133 changes: 133 additions & 0 deletions src/lib/esnext.iterator.d.ts
@@ -0,0 +1,133 @@
interface NativeIterator<T, TReturn = void, TNext = undefined> extends Iterator<T, TReturn, TNext> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The export {} trick mentioned in my earlier comment can address the abstract next() method definition.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The word choose "Native" is not so good. Do we have other options?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rbuckton had previously suggested Builtin, which I'm also fine with.

/**
* Returns this iterator.
*/
[Symbol.iterator](): NativeIterator<T, TReturn, TNext>;

/**
* Creates an iterator whose values are the result of applying the callback to the values from this iterator.
* @param callbackfn A function that accepts up to two arguments to be used to transform values from the underlying iterator.
*/
map<U>(callbackfn: (value: T, index: number) => U): NativeIterator<U>;

/**
* Creates an iterator whose values are those from this iterator for which the provided predicate returns true.
* @param predicate A function that accepts up to two arguments to be used to test values from the underlying iterator.
*/
filter<S extends T>(predicate: (value: T, index: number) => value is S): NativeIterator<S>;

/**
* Creates an iterator whose values are those from this iterator for which the provided predicate returns true.
* @param predicate A function that accepts up to two arguments to be used to test values from the underlying iterator.
*/
filter(predicate: (value: T, index: number) => unknown): NativeIterator<T>;

/**
* Creates an iterator whose values are the values from this iterator, stopping once the provided limit is reached.
* @param limit The maximum number of values to yield.
*/
take(limit: number): NativeIterator<T>;

/**
* Creates an iterator whose values are the values from this iterator after skipping the provided count.
* @param count The number of values to drop.
*/
drop(count: number): NativeIterator<T>;

/**
* Creates an iterator whose values are the result of applying the callback to the values from this iterator and then flattening the resulting iterators or iterables.
* @param callback A function that accepts up to two arguments to be used to transform values from the underlying iterator into new iterators or iterables to be flattened into the result.
*/
flatMap<U>(callback: (value: T, index: number) => Iterator<U> | Iterable<U>): NativeIterator<U>;

/**
* Calls the specified callback function for all the elements in this iterator. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
* @param callbackfn A function that accepts up to three arguments. The reduce method calls the callbackfn function one time for each element in the iterator.
* @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of a value from the iterator.
*/
reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number) => T): T;
reduce(callbackfn: (previousValue: T, currentValue: T, currentIndex: number) => T, initialValue: T): T;

/**
* Calls the specified callback function for all the elements in this iterator. The return value of the callback function is the accumulated result, and is provided as an argument in the next call to the callback function.
* @param callbackfn A function that accepts up to three arguments. The reduce method calls the callbackfn function one time for each element in the iterator.
* @param initialValue If initialValue is specified, it is used as the initial value to start the accumulation. The first call to the callbackfn function provides this value as an argument instead of a value from the iterator.
*/
reduce<U>(callbackfn: (previousValue: U, currentValue: T, currentIndex: number) => U, initialValue: U): U;

/**
* Creates a new array from the values yielded by this iterator.
*/
toArray(): Array<T>;

/**
* Performs the specified action for each element in the iterator.
* @param callbackfn A function that accepts up to two arguments. forEach calls the callbackfn function one time for each element in the iterator.
*/
forEach(callbackfn: (value: T, index: number) => void): void;

/**
* Determines whether the specified callback function returns true for any element of this iterator.
* @param predicate A function that accepts up to two arguments. The some method calls
* the predicate function for each element in this iterator until the predicate returns a value
* true, or until the end of the iterator.
*/
some(predicate: (value: T, index: number) => unknown): boolean;

/**
* Determines whether all the members of this iterator satisfy the specified test.
* @param predicate A function that accepts up to two arguments. The every method calls
* the predicate function for each element in this iterator until the predicate returns
* false, or until the end of this iterator.
*/
every(predicate: (value: T, index: number) => unknown): boolean;

/**
* Returns the value of the first element in this iterator where predicate is true, and undefined
* otherwise.
* @param predicate find calls predicate once for each element of this iterator, in
* order, until it finds one where predicate returns true. If such an element is found, find
* immediately returns that element value. Otherwise, find returns undefined.
*/
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";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest defining this as

Suggested change
readonly [Symbol.toStringTag]: "Iterator";
readonly [Symbol.toStringTag]: string;

otherwise subclasses of Iterator won't be able to redefine it.

}

interface IteratorConstructor {
/**
* Creates a native iterator from an iterator or iterable object.
* Returns its input if the input already inherits from the built-in Iterator class.
* @param value An iterator or iterable object to convert a native iterator.
*/
from<T>(value: Iterator<T> | Iterable<T>): NativeIterator<T>;
}

declare var Iterator: (abstract new <T>() => NativeIterator<T>) & IteratorConstructor;

// TODO BEFORE MERGING: update all existing IterableIterator-return methods to return NativeIterator
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

interface NativeIterator<T, TReturn = void, TNext = undefined> extends Iterator<T, TReturn, TNext> {
  [Symbol.iterator](): NativeIterator<T, TReturn, TNext>;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should I split that into a separate PR, or do it here?

// I have only done a couple so far, for illustration

interface Generator<T = unknown, TReturn = any, TNext = unknown> extends NativeIterator<T, TReturn, TNext> {
}

interface Array<T> {
/** Iterator */
[Symbol.iterator](): NativeIterator<T>;

/**
* Returns an iterable iterator of key, value pairs for every entry in the array
*/
entries(): NativeIterator<[number, T]>;

/**
* Returns an iterable iterator of keys in the array
*/
keys(): NativeIterator<number>;

/**
* Returns an iterable iterator of values in the array
*/
values(): NativeIterator<T>;
}
1 change: 1 addition & 0 deletions src/lib/libs.json
Expand Up @@ -79,6 +79,7 @@
"esnext.collection",
"esnext.array",
"esnext.regexp",
"esnext.iterator",
"decorators",
"decorators.legacy",
// Default libraries
Expand Down
18 changes: 9 additions & 9 deletions tests/baselines/reference/arrayFromAsync.symbols
Expand Up @@ -82,14 +82,14 @@ for await (const v of asyncGen(4)) {
const sameArr1 = await Array.fromAsync(arrLike);
>sameArr1 : Symbol(sameArr1, Decl(arrayFromAsync.ts, 25, 5))
>Array.fromAsync : Symbol(ArrayConstructor.fromAsync, Decl(lib.esnext.array.d.ts, --, --), Decl(lib.esnext.array.d.ts, --, --))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 4 more)
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 5 more)
>fromAsync : Symbol(ArrayConstructor.fromAsync, Decl(lib.esnext.array.d.ts, --, --), Decl(lib.esnext.array.d.ts, --, --))
>arrLike : Symbol(arrLike, Decl(arrayFromAsync.ts, 12, 5))

const sameArr2 = await Array.fromAsync([Promise.resolve(0), Promise.resolve(2), Promise.resolve(4), Promise.resolve(6)]);
>sameArr2 : Symbol(sameArr2, Decl(arrayFromAsync.ts, 26, 5))
>Array.fromAsync : Symbol(ArrayConstructor.fromAsync, Decl(lib.esnext.array.d.ts, --, --), Decl(lib.esnext.array.d.ts, --, --))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 4 more)
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 5 more)
>fromAsync : Symbol(ArrayConstructor.fromAsync, Decl(lib.esnext.array.d.ts, --, --), Decl(lib.esnext.array.d.ts, --, --))
>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
>Promise : Symbol(Promise, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2018.promise.d.ts, --, --))
Expand All @@ -107,14 +107,14 @@ const sameArr2 = await Array.fromAsync([Promise.resolve(0), Promise.resolve(2),
const sameArr3 = await Array.fromAsync(genPromises(4));
>sameArr3 : Symbol(sameArr3, Decl(arrayFromAsync.ts, 27, 5))
>Array.fromAsync : Symbol(ArrayConstructor.fromAsync, Decl(lib.esnext.array.d.ts, --, --), Decl(lib.esnext.array.d.ts, --, --))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 4 more)
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 5 more)
>fromAsync : Symbol(ArrayConstructor.fromAsync, Decl(lib.esnext.array.d.ts, --, --), Decl(lib.esnext.array.d.ts, --, --))
>genPromises : Symbol(genPromises, Decl(arrayFromAsync.ts, 4, 3))

const sameArr4 = await Array.fromAsync(asyncGen(4));
>sameArr4 : Symbol(sameArr4, Decl(arrayFromAsync.ts, 28, 5))
>Array.fromAsync : Symbol(ArrayConstructor.fromAsync, Decl(lib.esnext.array.d.ts, --, --), Decl(lib.esnext.array.d.ts, --, --))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 4 more)
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 5 more)
>fromAsync : Symbol(ArrayConstructor.fromAsync, Decl(lib.esnext.array.d.ts, --, --), Decl(lib.esnext.array.d.ts, --, --))
>asyncGen : Symbol(asyncGen, Decl(arrayFromAsync.ts, 0, 11))

Expand All @@ -127,7 +127,7 @@ Data.fromAsync = Array.fromAsync;
>Data : Symbol(Data, Decl(arrayFromAsync.ts, 28, 52), Decl(arrayFromAsync.ts, 30, 20))
>fromAsync : Symbol(Data.fromAsync, Decl(arrayFromAsync.ts, 30, 20))
>Array.fromAsync : Symbol(ArrayConstructor.fromAsync, Decl(lib.esnext.array.d.ts, --, --), Decl(lib.esnext.array.d.ts, --, --))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 4 more)
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 5 more)
>fromAsync : Symbol(ArrayConstructor.fromAsync, Decl(lib.esnext.array.d.ts, --, --), Decl(lib.esnext.array.d.ts, --, --))

const sameArr5 = await Data.fromAsync(asyncGen(4));
Expand All @@ -140,7 +140,7 @@ const sameArr5 = await Data.fromAsync(asyncGen(4));
const mapArr1 = await Array.fromAsync(asyncGen(4), v => v ** 2);
>mapArr1 : Symbol(mapArr1, Decl(arrayFromAsync.ts, 34, 5))
>Array.fromAsync : Symbol(ArrayConstructor.fromAsync, Decl(lib.esnext.array.d.ts, --, --), Decl(lib.esnext.array.d.ts, --, --))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 4 more)
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 5 more)
>fromAsync : Symbol(ArrayConstructor.fromAsync, Decl(lib.esnext.array.d.ts, --, --), Decl(lib.esnext.array.d.ts, --, --))
>asyncGen : Symbol(asyncGen, Decl(arrayFromAsync.ts, 0, 11))
>v : Symbol(v, Decl(arrayFromAsync.ts, 34, 50))
Expand All @@ -149,7 +149,7 @@ const mapArr1 = await Array.fromAsync(asyncGen(4), v => v ** 2);
const mapArr2 = await Array.fromAsync([0,2,4,6], v => Promise.resolve(v ** 2));
>mapArr2 : Symbol(mapArr2, Decl(arrayFromAsync.ts, 35, 5))
>Array.fromAsync : Symbol(ArrayConstructor.fromAsync, Decl(lib.esnext.array.d.ts, --, --), Decl(lib.esnext.array.d.ts, --, --))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 4 more)
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 5 more)
>fromAsync : Symbol(ArrayConstructor.fromAsync, Decl(lib.esnext.array.d.ts, --, --), Decl(lib.esnext.array.d.ts, --, --))
>v : Symbol(v, Decl(arrayFromAsync.ts, 35, 48))
>Promise.resolve : Symbol(PromiseConstructor.resolve, Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --), Decl(lib.es2015.promise.d.ts, --, --))
Expand All @@ -160,7 +160,7 @@ const mapArr2 = await Array.fromAsync([0,2,4,6], v => Promise.resolve(v ** 2));
const mapArr3 = await Array.fromAsync([0,2,4,6], v => v ** 2);
>mapArr3 : Symbol(mapArr3, Decl(arrayFromAsync.ts, 36, 5))
>Array.fromAsync : Symbol(ArrayConstructor.fromAsync, Decl(lib.esnext.array.d.ts, --, --), Decl(lib.esnext.array.d.ts, --, --))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 4 more)
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 5 more)
>fromAsync : Symbol(ArrayConstructor.fromAsync, Decl(lib.esnext.array.d.ts, --, --), Decl(lib.esnext.array.d.ts, --, --))
>v : Symbol(v, Decl(arrayFromAsync.ts, 36, 48))
>v : Symbol(v, Decl(arrayFromAsync.ts, 36, 48))
Expand All @@ -181,7 +181,7 @@ const badIterable = { [Symbol.iterator] () { throw err; } };
const badArray = await Array.fromAsync(badIterable);
>badArray : Symbol(badArray, Decl(arrayFromAsync.ts, 41, 5))
>Array.fromAsync : Symbol(ArrayConstructor.fromAsync, Decl(lib.esnext.array.d.ts, --, --), Decl(lib.esnext.array.d.ts, --, --))
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 4 more)
>Array : Symbol(Array, Decl(lib.es5.d.ts, --, --), Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.core.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --) ... and 5 more)
>fromAsync : Symbol(ArrayConstructor.fromAsync, Decl(lib.esnext.array.d.ts, --, --), Decl(lib.esnext.array.d.ts, --, --))
>badIterable : Symbol(badIterable, Decl(arrayFromAsync.ts, 39, 5))

1 change: 1 addition & 0 deletions tests/baselines/reference/awaitedType.types
@@ -1,6 +1,7 @@
//// [tests/cases/compiler/awaitedType.ts] ////

=== Performance Stats ===
Type Count: 1,000
Instantiation count: 25,000

=== awaitedType.ts ===
Expand Down
Expand Up @@ -1074,6 +1074,21 @@
"======== Module name '@typescript/lib-esnext/regexp' was not resolved. ========",
"File '/.ts/package.json' does not exist according to earlier cached lookups.",
"File '/package.json' does not exist according to earlier cached lookups.",
"======== Resolving module '@typescript/lib-esnext/iterator' from '/.src/__lib_node_modules_lookup_lib.esnext.iterator.d.ts__.ts'. ========",
"Explicitly specified module resolution kind: 'Node10'.",
"Loading module '@typescript/lib-esnext/iterator' from 'node_modules' folder, target file types: TypeScript, Declaration.",
"Searching all ancestor node_modules directories for preferred extensions: TypeScript, Declaration.",
"Directory '/.src/node_modules' does not exist, skipping all lookups in it.",
"Scoped package detected, looking in 'typescript__lib-esnext/iterator'",
"Directory '/node_modules' does not exist, skipping all lookups in it.",
"Scoped package detected, looking in 'typescript__lib-esnext/iterator'",
"Loading module '@typescript/lib-esnext/iterator' from 'node_modules' folder, target file types: JavaScript.",
"Searching all ancestor node_modules directories for fallback extensions: JavaScript.",
"Directory '/.src/node_modules' does not exist, skipping all lookups in it.",
"Directory '/node_modules' does not exist, skipping all lookups in it.",
"======== Module name '@typescript/lib-esnext/iterator' was not resolved. ========",
"File '/.ts/package.json' does not exist according to earlier cached lookups.",
"File '/package.json' does not exist according to earlier cached lookups.",
"======== Resolving module '@typescript/lib-dom' from '/.src/__lib_node_modules_lookup_lib.dom.d.ts__.ts'. ========",
"Explicitly specified module resolution kind: 'Node10'.",
"Loading module '@typescript/lib-dom' from 'node_modules' folder, target file types: TypeScript, Declaration.",
Expand Down