Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions tsc/internal/bundled/embed_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions tsc/internal/bundled/libs/lib.esnext.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ and limitations under the License.
/// <reference lib="esnext.typedarrays" />
/// <reference lib="esnext.temporal" />
/// <reference lib="esnext.date" />
/// <reference lib="esnext.iterator" />
119 changes: 119 additions & 0 deletions tsc/internal/bundled/libs/lib.esnext.iterator.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*! *****************************************************************************
Copyright (c) Microsoft Corporation. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License"); you may not use
this file except in compliance with the License. You may obtain a copy of the
License at http://www.apache.org/licenses/LICENSE-2.0

THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED
WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE,
MERCHANTABILITY OR NON-INFRINGEMENT.

See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */


/// <reference lib="es2025.iterator" />

export {};

interface IteratorZipShortestOptions {
/**
* Stops when any input is exhausted.
*/
mode?: "shortest";
}

interface IteratorZipLongestOptions<T> {
/**
* Continues until every input is exhausted.
*/
mode: "longest";

/**
* Values used when an input is exhausted before the others.
*/
padding?: T;
}

interface IteratorZipStrictOptions {
/**
* Requires every input to yield the same number of values.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Suggested change
* Requires every input to yield the same number of values.
* Requires every input to yield the same number of values.
* If not, a `TypeError` will be thrown when an input is exhausted before others.

* If not, a `TypeError` will be thrown when an input is exhausted before others.
*/
mode: "strict";
}

type IteratorZipOptions<T> =
| IteratorZipShortestOptions
| IteratorZipLongestOptions<T>
| IteratorZipStrictOptions;

type IteratorInput<T> = Iterable<T> | Iterator<T>;

type IteratorInputTuple = readonly [] | readonly [IteratorInput<unknown>, ...IteratorInput<unknown>[]];

type IteratorYield<T> = T extends IteratorInput<infer U> ? U : never;

type IteratorZipResult<T, TExtra = never> = {
-readonly [K in keyof T]: IteratorYield<T[K]> | TExtra;
};

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Is there a difference in these mapped types other than the constraint? I think you can unify them.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done - unified both types into IteratorZipResult


declare global {
interface IteratorObject<T, TReturn, TNext> {
/**
* Creates an iterator whose values are arrays containing successive values from this iterator.
* @param chunkSize The maximum number of values in each array.
*/
chunks(chunkSize: number): IteratorObject<T[], undefined, unknown>;

/**
* Creates a string by concatenating the values of this iterator, separated by the specified separator.
* `null` and `undefined` values contribute an empty string.
* @param separator A string used to separate values. If omitted, a comma is used.
*/
join(separator?: string): string;

/**
* Determines whether this iterator yields the specified value using SameValueZero comparison.
* @param searchElement The value to locate.
* @param skippedElements The number of values to skip before searching.
*/
includes(searchElement: T, skippedElements?: number): boolean;
}

interface IteratorConstructor {
/**
* Creates an iterator whose values are arrays containing values yielded at the same position by each input iterator or iterable.
* @param iterables An iterable of iterators or iterables to zip.
* @param options Controls how differing input lengths are handled.
*/
zip(iterables: readonly [], options?: IteratorZipOptions<Iterable<unknown>>): IteratorObject<never, undefined, unknown>;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

It is a little funny that we need this overload. I don't know what we'd do instead other than a conditional.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I actually don't see any test for an empty list of iterables.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I've added additional tests


/**
* Creates an iterator whose values are arrays containing values yielded at the same position by each input iterator or iterable.
* @param iterables An iterable of iterators or iterables to zip.
* @param options Controls how differing input lengths are handled.
*/
zip<T extends IteratorInputTuple>(iterables: T, options: IteratorZipLongestOptions<NoInfer<IteratorZipResult<T>>> & { padding: NoInfer<IteratorZipResult<T>>; }): IteratorObject<IteratorZipResult<T>, undefined, unknown>;
zip<T extends readonly IteratorInput<unknown>[] | []>(iterables: T, options?: IteratorZipShortestOptions | IteratorZipStrictOptions): IteratorObject<IteratorZipResult<T>, undefined, unknown>;
zip<T extends readonly IteratorInput<unknown>[] | []>(iterables: T, options: IteratorZipOptions<NoInfer<Partial<IteratorZipResult<T>>>>): IteratorObject<IteratorZipResult<T, undefined>, undefined, unknown>;

/**
* Creates an iterator whose values are arrays containing values yielded at the same position by each input iterator or iterable.
* @param iterables An iterable of iterators or iterables to zip.
* @param options Controls how differing input lengths are handled.
*/
zip<T extends IteratorInput<unknown>>(iterables: Iterable<T>, options?: IteratorZipShortestOptions | IteratorZipStrictOptions): IteratorObject<IteratorYield<T>[], undefined, unknown>;
zip<T extends IteratorInput<unknown>>(iterables: Iterable<T>, options: IteratorZipOptions<NoInfer<Iterable<IteratorYield<T>>>>): IteratorObject<(IteratorYield<T> | undefined)[], undefined, unknown>;

/**
* Creates an iterator whose values are objects containing values yielded at the same position by each iterator or iterable in the input object.
* @param iterables An object whose enumerable own properties contain iterators or iterables to zip.
* @param options Controls how differing input lengths are handled.
*/
zipKeyed<T extends object>(iterables: T & Record<keyof T, IteratorInput<unknown>>, options?: IteratorZipShortestOptions | (IteratorZipLongestOptions<NoInfer<IteratorZipResult<T>>> & { padding: NoInfer<IteratorZipResult<T>>; }) | IteratorZipStrictOptions): IteratorObject<IteratorZipResult<T>, undefined, unknown>;
zipKeyed<T extends object>(iterables: T & Record<keyof T, IteratorInput<unknown>>, options: IteratorZipOptions<NoInfer<Partial<IteratorZipResult<T>>>>): IteratorObject<IteratorZipResult<T, undefined>, undefined, unknown>;
}
}
1 change: 1 addition & 0 deletions tsc/internal/bundled/libs_generated.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions tsc/internal/compiler/program_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ var esnextLibs = []string{
"lib.es2025.iterator.d.ts",
"lib.es2025.promise.d.ts",
"lib.es2025.regexp.d.ts",
"lib.esnext.iterator.d.ts",
"lib.esnext.array.d.ts",
"lib.esnext.collection.d.ts",
"lib.esnext.date.d.ts",
Expand Down
2 changes: 1 addition & 1 deletion tsc/internal/tsoptions/enummaps.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ var LibMap = collections.NewOrderedMapFromList([]collections.MapEntry[string, an
{Key: "esnext.regexp", Value: "lib.es2024.regexp.d.ts"},
{Key: "esnext.string", Value: "lib.es2024.string.d.ts"},
{Key: "esnext.float16", Value: "lib.es2025.float16.d.ts"},
{Key: "esnext.iterator", Value: "lib.es2025.iterator.d.ts"},
{Key: "esnext.promise", Value: "lib.es2025.promise.d.ts"},
// ESNext By-feature options
{Key: "esnext.iterator", Value: "lib.esnext.iterator.d.ts"},
{Key: "esnext.array", Value: "lib.esnext.array.d.ts"},
{Key: "esnext.collection", Value: "lib.esnext.collection.d.ts"},
{Key: "esnext.date", Value: "lib.esnext.date.d.ts"},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -184,7 +184,7 @@ const iter1 = Iterator.from(g1);

declare const iter2: IteratorObject<string>;
>iter2 : Symbol(iter2, Decl(builtinIterator.ts, 71, 13))
>IteratorObject : Symbol(IteratorObject, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.esnext.disposable.d.ts, --, --), Decl(lib.es2025.iterator.d.ts, --, --))
>IteratorObject : Symbol(IteratorObject, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.esnext.disposable.d.ts, --, --), Decl(lib.es2025.iterator.d.ts, --, --), Decl(lib.esnext.iterator.d.ts, --, --))

const iter3 = iter2.flatMap(() => g1);
>iter3 : Symbol(iter3, Decl(builtinIterator.ts, 72, 5))
Expand Down
12 changes: 6 additions & 6 deletions tsc/testdata/baselines/reference/compiler/builtinIterator.types
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
const iterator = Iterator.from([0, 1, 2]);
>iterator : IteratorObject<number, undefined, unknown>
>Iterator.from([0, 1, 2]) : IteratorObject<number, undefined, unknown>
>Iterator.from : <T>(value: Iterator<T, unknown, undefined> | Iterable<T, unknown, undefined>) => IteratorObject<T, undefined, unknown>
>Iterator.from : <T>(value: Iterable<T, unknown, undefined> | Iterator<T, unknown, undefined>) => IteratorObject<T, undefined, unknown>
>Iterator : IteratorConstructor
>from : <T>(value: Iterator<T, unknown, undefined> | Iterable<T, unknown, undefined>) => IteratorObject<T, undefined, unknown>
>from : <T>(value: Iterable<T, unknown, undefined> | Iterator<T, unknown, undefined>) => IteratorObject<T, undefined, unknown>
>[0, 1, 2] : number[]
>0 : 0
>1 : 1
Expand Down Expand Up @@ -52,9 +52,9 @@ const zero = iterator.filter(isZero);
const iteratorFromBare = Iterator.from({
>iteratorFromBare : IteratorObject<string, undefined, unknown>
>Iterator.from({ next() { return { done: Math.random() < .5, value: "a string", }; },}) : IteratorObject<string, undefined, unknown>
>Iterator.from : <T>(value: Iterator<T, unknown, undefined> | Iterable<T, unknown, undefined>) => IteratorObject<T, undefined, unknown>
>Iterator.from : <T>(value: Iterable<T, unknown, undefined> | Iterator<T, unknown, undefined>) => IteratorObject<T, undefined, unknown>
>Iterator : IteratorConstructor
>from : <T>(value: Iterator<T, unknown, undefined> | Iterable<T, unknown, undefined>) => IteratorObject<T, undefined, unknown>
>from : <T>(value: Iterable<T, unknown, undefined> | Iterator<T, unknown, undefined>) => IteratorObject<T, undefined, unknown>
>{ next() { return { done: Math.random() < .5, value: "a string", }; },} : { next(): { done: boolean; value: string; }; }

next() {
Expand Down Expand Up @@ -244,9 +244,9 @@ declare const g1: Generator<string, number, boolean>;
const iter1 = Iterator.from(g1);
>iter1 : IteratorObject<string, undefined, unknown>
>Iterator.from(g1) : IteratorObject<string, undefined, unknown>
>Iterator.from : <T>(value: Iterator<T, unknown, undefined> | Iterable<T, unknown, undefined>) => IteratorObject<T, undefined, unknown>
>Iterator.from : <T>(value: Iterable<T, unknown, undefined> | Iterator<T, unknown, undefined>) => IteratorObject<T, undefined, unknown>
>Iterator : IteratorConstructor
>from : <T>(value: Iterator<T, unknown, undefined> | Iterable<T, unknown, undefined>) => IteratorObject<T, undefined, unknown>
>from : <T>(value: Iterable<T, unknown, undefined> | Iterator<T, unknown, undefined>) => IteratorObject<T, undefined, unknown>
>g1 : Generator<string, number, boolean>

declare const iter2: IteratorObject<string>;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
iteratorChunks.ts(3,33): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.


==== iteratorChunks.ts (1 errors) ====
const chunks: number[][] = Iterator.from([1, 2, 3]).chunks(2).toArray();

Iterator.from([1, 2, 3]).chunks("2");
~~~
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.

12 changes: 12 additions & 0 deletions tsc/testdata/baselines/reference/compiler/iteratorChunks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//// [tests/cases/compiler/iteratorChunks.ts] ////

//// [iteratorChunks.ts]
const chunks: number[][] = Iterator.from([1, 2, 3]).chunks(2).toArray();

Iterator.from([1, 2, 3]).chunks("2");


//// [iteratorChunks.js]
"use strict";
const chunks = Iterator.from([1, 2, 3]).chunks(2).toArray();
Iterator.from([1, 2, 3]).chunks("2");
20 changes: 20 additions & 0 deletions tsc/testdata/baselines/reference/compiler/iteratorChunks.symbols
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//// [tests/cases/compiler/iteratorChunks.ts] ////

=== iteratorChunks.ts ===
const chunks: number[][] = Iterator.from([1, 2, 3]).chunks(2).toArray();
>chunks : Symbol(chunks, Decl(iteratorChunks.ts, 0, 5))
>Iterator.from([1, 2, 3]).chunks(2).toArray : Symbol(IteratorObject.toArray, Decl(lib.es2025.iterator.d.ts, --, --))
>Iterator.from([1, 2, 3]).chunks : Symbol(IteratorObject.chunks, Decl(lib.esnext.iterator.d.ts, --, --))
>Iterator.from : Symbol(IteratorConstructor.from, Decl(lib.es2025.iterator.d.ts, --, --))
>Iterator : Symbol(Iterator, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2025.iterator.d.ts, --, --))
>from : Symbol(IteratorConstructor.from, Decl(lib.es2025.iterator.d.ts, --, --))
>chunks : Symbol(IteratorObject.chunks, Decl(lib.esnext.iterator.d.ts, --, --))
>toArray : Symbol(IteratorObject.toArray, Decl(lib.es2025.iterator.d.ts, --, --))

Iterator.from([1, 2, 3]).chunks("2");
>Iterator.from([1, 2, 3]).chunks : Symbol(IteratorObject.chunks, Decl(lib.esnext.iterator.d.ts, --, --))
>Iterator.from : Symbol(IteratorConstructor.from, Decl(lib.es2025.iterator.d.ts, --, --))
>Iterator : Symbol(Iterator, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2025.iterator.d.ts, --, --))
>from : Symbol(IteratorConstructor.from, Decl(lib.es2025.iterator.d.ts, --, --))
>chunks : Symbol(IteratorObject.chunks, Decl(lib.esnext.iterator.d.ts, --, --))

35 changes: 35 additions & 0 deletions tsc/testdata/baselines/reference/compiler/iteratorChunks.types
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//// [tests/cases/compiler/iteratorChunks.ts] ////

=== iteratorChunks.ts ===
const chunks: number[][] = Iterator.from([1, 2, 3]).chunks(2).toArray();
>chunks : number[][]
>Iterator.from([1, 2, 3]).chunks(2).toArray() : number[][]
>Iterator.from([1, 2, 3]).chunks(2).toArray : () => number[][]
>Iterator.from([1, 2, 3]).chunks(2) : IteratorObject<number[], undefined, unknown>
>Iterator.from([1, 2, 3]).chunks : (chunkSize: number) => IteratorObject<number[], undefined, unknown>
>Iterator.from([1, 2, 3]) : IteratorObject<number, undefined, unknown>
>Iterator.from : <T>(value: Iterable<T, unknown, undefined> | Iterator<T, unknown, undefined>) => IteratorObject<T, undefined, unknown>
>Iterator : IteratorConstructor
>from : <T>(value: Iterable<T, unknown, undefined> | Iterator<T, unknown, undefined>) => IteratorObject<T, undefined, unknown>
>[1, 2, 3] : number[]
>1 : 1
>2 : 2
>3 : 3
>chunks : (chunkSize: number) => IteratorObject<number[], undefined, unknown>
>2 : 2
>toArray : () => number[][]

Iterator.from([1, 2, 3]).chunks("2");
>Iterator.from([1, 2, 3]).chunks("2") : IteratorObject<number[], undefined, unknown>
>Iterator.from([1, 2, 3]).chunks : (chunkSize: number) => IteratorObject<number[], undefined, unknown>
>Iterator.from([1, 2, 3]) : IteratorObject<number, undefined, unknown>
>Iterator.from : <T>(value: Iterable<T, unknown, undefined> | Iterator<T, unknown, undefined>) => IteratorObject<T, undefined, unknown>
>Iterator : IteratorConstructor
>from : <T>(value: Iterable<T, unknown, undefined> | Iterator<T, unknown, undefined>) => IteratorObject<T, undefined, unknown>
>[1, 2, 3] : number[]
>1 : 1
>2 : 2
>3 : 3
>chunks : (chunkSize: number) => IteratorObject<number[], undefined, unknown>
>"2" : "2"

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
iteratorIncludes.ts(4,35): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.
iteratorIncludes.ts(6,38): error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.


==== iteratorIncludes.ts (2 errors) ====
const includes: boolean = Iterator.from([1, 2, 3]).includes(2);
const includesAfterSkipping: boolean = Iterator.from([1, 2, 3]).includes(2, 1);

Iterator.from([1, 2, 3]).includes("1");
~~~
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.

Iterator.from([1, 2, 3]).includes(2, "1");
~~~
!!! error TS2345: Argument of type 'string' is not assignable to parameter of type 'number'.

17 changes: 17 additions & 0 deletions tsc/testdata/baselines/reference/compiler/iteratorIncludes.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
//// [tests/cases/compiler/iteratorIncludes.ts] ////

//// [iteratorIncludes.ts]
const includes: boolean = Iterator.from([1, 2, 3]).includes(2);
const includesAfterSkipping: boolean = Iterator.from([1, 2, 3]).includes(2, 1);

Iterator.from([1, 2, 3]).includes("1");

Iterator.from([1, 2, 3]).includes(2, "1");


//// [iteratorIncludes.js]
"use strict";
const includes = Iterator.from([1, 2, 3]).includes(2);
const includesAfterSkipping = Iterator.from([1, 2, 3]).includes(2, 1);
Iterator.from([1, 2, 3]).includes("1");
Iterator.from([1, 2, 3]).includes(2, "1");
Loading