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

Improve generic type signature of Iterator.from() #59927

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
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
8 changes: 4 additions & 4 deletions src/lib/esnext.iterator.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@
export {};

// Abstract type that allows us to mark `next` as `abstract`
declare abstract class Iterator<T, TResult = undefined, TNext = unknown> { // eslint-disable-line @typescript-eslint/no-unsafe-declaration-merging
abstract next(value?: TNext): IteratorResult<T, TResult>;
declare abstract class Iterator<T, TReturn = undefined, TNext = unknown> { // eslint-disable-line @typescript-eslint/no-unsafe-declaration-merging
abstract next(value?: TNext): IteratorResult<T, TReturn>;
}

// Merge all members of `IteratorObject<T>` into `Iterator<T>`
interface Iterator<T, TResult, TNext> extends globalThis.IteratorObject<T, TResult, TNext> {}
interface Iterator<T, TReturn, TNext> extends globalThis.IteratorObject<T, TReturn, TNext> {}

// Capture the `Iterator` constructor in a type we can use in the `extends` clause of `IteratorConstructor`.
type IteratorObjectConstructor = typeof Iterator;
Expand Down Expand Up @@ -123,7 +123,7 @@ declare global {
* 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, unknown, undefined> | Iterable<T, unknown, undefined>): IteratorObject<T, undefined, unknown>;
from<T, TReturn = any>(value: Iterator<T, TReturn, undefined> | Iterable<T, TReturn, undefined>): IteratorObject<T, TReturn, unknown>;
}

var Iterator: IteratorConstructor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ async function f() {
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>Iterator.from(i) : IteratorObject<string, undefined, unknown>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>Iterator.from : <T>(value: Iterator<T, unknown, undefined> | Iterable<T, unknown, undefined>) => IteratorObject<T, undefined, unknown>
> : ^ ^^ ^^ ^^^^^
>Iterator.from : <T, TReturn = any>(value: Iterator<T, TReturn, undefined> | Iterable<T, TReturn, undefined>) => IteratorObject<T, TReturn, unknown>
> : ^ ^^ ^^^^^^^^ ^^ ^^^^^
>Iterator : IteratorConstructor
> : ^^^^^^^^^^^^^^^^^^^
>from : <T>(value: Iterator<T, unknown, undefined> | Iterable<T, unknown, undefined>) => IteratorObject<T, undefined, unknown>
> : ^ ^^ ^^ ^^^^^
>from : <T, TReturn = any>(value: Iterator<T, TReturn, undefined> | Iterable<T, TReturn, undefined>) => IteratorObject<T, TReturn, unknown>
> : ^ ^^ ^^^^^^^^ ^^ ^^^^^
>i : Iterator<string, undefined, any>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
23 changes: 16 additions & 7 deletions tests/baselines/reference/builtinIterator.errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ builtinIterator.ts(60,3): error TS2416: Property 'next' in type 'BadIterator3' i
Type '{ done: boolean; value: number; }' is not assignable to type 'IteratorYieldResult<number>'.
Types of property 'done' are incompatible.
Type 'boolean' is not assignable to type 'false'.
builtinIterator.ts(70,29): error TS2345: Argument of type 'Generator<string, number, boolean>' is not assignable to parameter of type 'Iterator<string, unknown, undefined> | Iterable<string, unknown, undefined>'.
Type 'Generator<string, number, boolean>' is not assignable to type 'Iterator<string, unknown, undefined>'.
builtinIterator.ts(70,29): error TS2345: Argument of type 'Generator<string, number, boolean>' is not assignable to parameter of type 'Iterator<string, number, undefined> | Iterable<string, number, undefined>'.
Type 'Generator<string, number, boolean>' is not assignable to type 'Iterator<string, number, undefined>'.
Types of property 'next' are incompatible.
Type '(...[value]: [] | [boolean]) => IteratorResult<string, number>' is not assignable to type '(...[value]: [] | [undefined]) => IteratorResult<string, unknown>'.
Type '(...[value]: [] | [boolean]) => IteratorResult<string, number>' is not assignable to type '(...[value]: [] | [undefined]) => IteratorResult<string, number>'.
Types of parameters '__0' and '__0' are incompatible.
Type '[] | [undefined]' is not assignable to type '[] | [boolean]'.
Type '[undefined]' is not assignable to type '[] | [boolean]'.
Expand Down Expand Up @@ -139,10 +139,10 @@ builtinIterator.ts(73,35): error TS2322: Type 'Generator<string, number, boolean
declare const g1: Generator<string, number, boolean>;
const iter1 = Iterator.from(g1);
~~
!!! error TS2345: Argument of type 'Generator<string, number, boolean>' is not assignable to parameter of type 'Iterator<string, unknown, undefined> | Iterable<string, unknown, undefined>'.
!!! error TS2345: Type 'Generator<string, number, boolean>' is not assignable to type 'Iterator<string, unknown, undefined>'.
!!! error TS2345: Argument of type 'Generator<string, number, boolean>' is not assignable to parameter of type 'Iterator<string, number, undefined> | Iterable<string, number, undefined>'.
!!! error TS2345: Type 'Generator<string, number, boolean>' is not assignable to type 'Iterator<string, number, undefined>'.
!!! error TS2345: Types of property 'next' are incompatible.
!!! error TS2345: Type '(...[value]: [] | [boolean]) => IteratorResult<string, number>' is not assignable to type '(...[value]: [] | [undefined]) => IteratorResult<string, unknown>'.
!!! error TS2345: Type '(...[value]: [] | [boolean]) => IteratorResult<string, number>' is not assignable to type '(...[value]: [] | [undefined]) => IteratorResult<string, number>'.
!!! error TS2345: Types of parameters '__0' and '__0' are incompatible.
!!! error TS2345: Type '[] | [undefined]' is not assignable to type '[] | [boolean]'.
!!! error TS2345: Type '[undefined]' is not assignable to type '[] | [boolean]'.
Expand All @@ -161,4 +161,13 @@ builtinIterator.ts(73,35): error TS2322: Type 'Generator<string, number, boolean
!!! error TS2322: Type '[undefined]' is not assignable to type '[] | [boolean]'.
!!! error TS2322: Type '[undefined]' is not assignable to type '[boolean]'.
!!! error TS2322: Type 'undefined' is not assignable to type 'boolean'.
!!! related TS6502 lib.esnext.iterator.d.ts:--:--: The expected type comes from the return type of this signature.
!!! related TS6502 lib.esnext.iterator.d.ts:--:--: The expected type comes from the return type of this signature.

// Iterator.from pass-through of return value
const customGenerator = function* () {
return 42;
}();
const withHelpers = Iterator.from(customGenerator);
const result = withHelpers.next();
const resultValue: number = result.value; // this should work

18 changes: 17 additions & 1 deletion tests/baselines/reference/builtinIterator.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,16 @@ declare const g1: Generator<string, number, boolean>;
const iter1 = Iterator.from(g1);

declare const iter2: IteratorObject<string>;
const iter3 = iter2.flatMap(() => g1);
const iter3 = iter2.flatMap(() => g1);

// Iterator.from pass-through of return value
const customGenerator = function* () {
return 42;
}();
const withHelpers = Iterator.from(customGenerator);
const result = withHelpers.next();
const resultValue: number = result.value; // this should work


//// [builtinIterator.js]
"use strict";
Expand Down Expand Up @@ -134,3 +143,10 @@ class BadIterator3 extends Iterator {
}
const iter1 = Iterator.from(g1);
const iter3 = iter2.flatMap(() => g1);
// Iterator.from pass-through of return value
const customGenerator = function* () {
return 42;
}();
const withHelpers = Iterator.from(customGenerator);
const result = withHelpers.next();
const resultValue = result.value; // this should work
25 changes: 25 additions & 0 deletions tests/baselines/reference/builtinIterator.symbols
Original file line number Diff line number Diff line change
Expand Up @@ -193,3 +193,28 @@ const iter3 = iter2.flatMap(() => g1);
>flatMap : Symbol(IteratorObject.flatMap, Decl(lib.esnext.iterator.d.ts, --, --))
>g1 : Symbol(g1, Decl(builtinIterator.ts, 68, 13))

// Iterator.from pass-through of return value
const customGenerator = function* () {
>customGenerator : Symbol(customGenerator, Decl(builtinIterator.ts, 75, 5))

return 42;
}();
const withHelpers = Iterator.from(customGenerator);
>withHelpers : Symbol(withHelpers, Decl(builtinIterator.ts, 78, 5))
>Iterator.from : Symbol(IteratorConstructor.from, Decl(lib.esnext.iterator.d.ts, --, --))
>Iterator : Symbol(Iterator, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.esnext.iterator.d.ts, --, --))
>from : Symbol(IteratorConstructor.from, Decl(lib.esnext.iterator.d.ts, --, --))
>customGenerator : Symbol(customGenerator, Decl(builtinIterator.ts, 75, 5))

const result = withHelpers.next();
>result : Symbol(result, Decl(builtinIterator.ts, 79, 5))
>withHelpers.next : Symbol(Iterator.next, Decl(lib.es2015.iterable.d.ts, --, --))
>withHelpers : Symbol(withHelpers, Decl(builtinIterator.ts, 78, 5))
>next : Symbol(Iterator.next, Decl(lib.es2015.iterable.d.ts, --, --))

const resultValue: number = result.value; // this should work
>resultValue : Symbol(resultValue, Decl(builtinIterator.ts, 80, 5))
>result.value : Symbol(value, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --))
>result : Symbol(result, Decl(builtinIterator.ts, 79, 5))
>value : Symbol(value, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --))

90 changes: 70 additions & 20 deletions tests/baselines/reference/builtinIterator.types
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ const iterator = Iterator.from([0, 1, 2]);
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>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, TReturn = any>(value: Iterator<T, TReturn, undefined> | Iterable<T, TReturn, undefined>) => IteratorObject<T, TReturn, unknown>
> : ^ ^^ ^^^^^^^^ ^^ ^^^^^
>Iterator : IteratorConstructor
> : ^^^^^^^^^^^^^^^^^^^
>from : <T>(value: Iterator<T, unknown, undefined> | Iterable<T, unknown, undefined>) => IteratorObject<T, undefined, unknown>
> : ^ ^^ ^^ ^^^^^
>from : <T, TReturn = any>(value: Iterator<T, TReturn, undefined> | Iterable<T, TReturn, undefined>) => IteratorObject<T, TReturn, unknown>
> : ^ ^^ ^^^^^^^^ ^^ ^^^^^
>[0, 1, 2] : number[]
> : ^^^^^^^^
>0 : 0
Expand Down Expand Up @@ -86,16 +86,16 @@ 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>
> : ^ ^^ ^^ ^^^^^
>iteratorFromBare : IteratorObject<string, string, unknown>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>Iterator.from({ next() { return { done: Math.random() < .5, value: "a string", }; },}) : IteratorObject<string, string, unknown>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>Iterator.from : <T, TReturn = any>(value: Iterator<T, TReturn, undefined> | Iterable<T, TReturn, undefined>) => IteratorObject<T, TReturn, unknown>
> : ^ ^^ ^^^^^^^^ ^^ ^^^^^
>Iterator : IteratorConstructor
> : ^^^^^^^^^^^^^^^^^^^
>from : <T>(value: Iterator<T, unknown, undefined> | Iterable<T, unknown, undefined>) => IteratorObject<T, undefined, unknown>
> : ^ ^^ ^^ ^^^^^
>from : <T, TReturn = any>(value: Iterator<T, TReturn, undefined> | Iterable<T, TReturn, undefined>) => IteratorObject<T, TReturn, unknown>
> : ^ ^^ ^^^^^^^^ ^^ ^^^^^
>{ next() { return { done: Math.random() < .5, value: "a string", }; },} : { next(): { done: boolean; value: string; }; }
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -393,16 +393,16 @@ 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>
> : ^ ^^ ^^ ^^^^^
>iter1 : IteratorObject<string, number, unknown>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>Iterator.from(g1) : IteratorObject<string, number, unknown>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>Iterator.from : <T, TReturn = any>(value: Iterator<T, TReturn, undefined> | Iterable<T, TReturn, undefined>) => IteratorObject<T, TReturn, unknown>
> : ^ ^^ ^^^^^^^^ ^^ ^^^^^
>Iterator : IteratorConstructor
> : ^^^^^^^^^^^^^^^^^^^
>from : <T>(value: Iterator<T, unknown, undefined> | Iterable<T, unknown, undefined>) => IteratorObject<T, undefined, unknown>
> : ^ ^^ ^^ ^^^^^
>from : <T, TReturn = any>(value: Iterator<T, TReturn, undefined> | Iterable<T, TReturn, undefined>) => IteratorObject<T, TReturn, unknown>
> : ^ ^^ ^^^^^^^^ ^^ ^^^^^
>g1 : Generator<string, number, boolean>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand All @@ -426,3 +426,53 @@ const iter3 = iter2.flatMap(() => g1);
>g1 : Generator<string, number, boolean>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

// Iterator.from pass-through of return value
const customGenerator = function* () {
>customGenerator : Generator<never, number, unknown>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>function* () { return 42;}() : Generator<never, number, unknown>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>function* () { return 42;} : () => Generator<never, number, unknown>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

return 42;
>42 : 42
> : ^^

}();
const withHelpers = Iterator.from(customGenerator);
>withHelpers : IteratorObject<never, number, unknown>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>Iterator.from(customGenerator) : IteratorObject<never, number, unknown>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>Iterator.from : <T, TReturn = any>(value: Iterator<T, TReturn, undefined> | Iterable<T, TReturn, undefined>) => IteratorObject<T, TReturn, unknown>
> : ^ ^^ ^^^^^^^^ ^^ ^^^^^
>Iterator : IteratorConstructor
> : ^^^^^^^^^^^^^^^^^^^
>from : <T, TReturn = any>(value: Iterator<T, TReturn, undefined> | Iterable<T, TReturn, undefined>) => IteratorObject<T, TReturn, unknown>
> : ^ ^^ ^^^^^^^^ ^^ ^^^^^
>customGenerator : Generator<never, number, unknown>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

const result = withHelpers.next();
>result : IteratorResult<never, number>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>withHelpers.next() : IteratorResult<never, number>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>withHelpers.next : (...[value]: [] | [unknown]) => IteratorResult<never, number>
> : ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>withHelpers : IteratorObject<never, number, unknown>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>next : (...[value]: [] | [unknown]) => IteratorResult<never, number>
> : ^^^^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

const resultValue: number = result.value; // this should work
>resultValue : number
> : ^^^^^^
>result.value : number
> : ^^^^^^
>result : IteratorResult<never, number>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>value : number
> : ^^^^^^

Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ function f() {
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>Iterator.from(i) : IteratorObject<string, undefined, unknown>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>Iterator.from : <T>(value: Iterator<T, unknown, undefined> | Iterable<T, unknown, undefined>) => IteratorObject<T, undefined, unknown>
> : ^ ^^ ^^ ^^^^^
>Iterator.from : <T, TReturn = any>(value: Iterator<T, TReturn, undefined> | Iterable<T, TReturn, undefined>) => IteratorObject<T, TReturn, unknown>
> : ^ ^^ ^^^^^^^^ ^^ ^^^^^
>Iterator : IteratorConstructor
> : ^^^^^^^^^^^^^^^^^^^
>from : <T>(value: Iterator<T, unknown, undefined> | Iterable<T, unknown, undefined>) => IteratorObject<T, undefined, unknown>
> : ^ ^^ ^^ ^^^^^
>from : <T, TReturn = any>(value: Iterator<T, TReturn, undefined> | Iterable<T, TReturn, undefined>) => IteratorObject<T, TReturn, unknown>
> : ^ ^^ ^^^^^^^^ ^^ ^^^^^
>i : Iterator<string, undefined, any>
> : ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Expand Down
10 changes: 9 additions & 1 deletion tests/cases/compiler/builtinIterator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,12 @@ declare const g1: Generator<string, number, boolean>;
const iter1 = Iterator.from(g1);

declare const iter2: IteratorObject<string>;
const iter3 = iter2.flatMap(() => g1);
const iter3 = iter2.flatMap(() => g1);

// Iterator.from pass-through of return value
const customGenerator = function* () {
return 42;
}();
const withHelpers = Iterator.from(customGenerator);
const result = withHelpers.next();
const resultValue: number = result.value; // this should work