diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 5658109668c2c..6f7c7cf4e99da 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -905,6 +905,7 @@ namespace ts { let deferredGlobalGeneratorType: GenericType; let deferredGlobalIteratorYieldResultType: GenericType; let deferredGlobalIteratorReturnResultType: GenericType; + let deferredGlobalIteratorVoidReturnResultType: ObjectType; let deferredGlobalAsyncIterableType: GenericType; let deferredGlobalAsyncIteratorType: GenericType; let deferredGlobalAsyncIterableIteratorType: GenericType; @@ -12564,6 +12565,10 @@ namespace ts { return deferredGlobalIteratorReturnResultType || (deferredGlobalIteratorReturnResultType = getGlobalType("IteratorReturnResult" as __String, /*arity*/ 1, reportErrors)) || emptyGenericType; } + function getGlobalIteratorVoidReturnResultType(reportErrors: boolean) { + return deferredGlobalIteratorVoidReturnResultType || (deferredGlobalIteratorVoidReturnResultType = getGlobalType("IteratorVoidReturnResult" as __String, /*arity*/ 0, reportErrors)) || emptyObjectType; + } + function getGlobalTypeOrUndefined(name: __String, arity = 0): ObjectType | undefined { const symbol = getGlobalSymbol(name, SymbolFlags.Type, /*diagnostic*/ undefined); return symbol && getTypeOfGlobalSymbol(symbol, arity); @@ -34431,6 +34436,9 @@ namespace ts { const returnType = getTypeArguments(type as GenericType)[0]; return setCachedIterationTypes(type, "iterationTypesOfIteratorResult", createIterationTypes(/*yieldType*/ undefined, returnType, /*nextType*/ undefined)); } + if (isReferenceToType(type, getGlobalIteratorVoidReturnResultType(/*reportErrors*/ false))) { + return setCachedIterationTypes(type, "iterationTypesOfIteratorResult", createIterationTypes(/*yieldType*/ undefined, voidType, /*nextType*/ undefined)); + } // Choose any constituents that can produce the requested iteration type. const yieldIteratorResult = filterType(type, isYieldIteratorResult); diff --git a/src/lib/es2015.iterable.d.ts b/src/lib/es2015.iterable.d.ts index da6bec04adf8e..79531cf48eeeb 100644 --- a/src/lib/es2015.iterable.d.ts +++ b/src/lib/es2015.iterable.d.ts @@ -18,7 +18,15 @@ interface IteratorReturnResult { value: TReturn; } -type IteratorResult = IteratorYieldResult | IteratorReturnResult; +interface IteratorVoidReturnResult { + done: true; + value?: void; +} + +type IteratorResult = + | IteratorYieldResult + | IteratorReturnResult + | (TReturn extends void ? IteratorVoidReturnResult : never); interface Iterator { // NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places. diff --git a/tests/baselines/reference/iteratorVoidResult.symbols b/tests/baselines/reference/iteratorVoidResult.symbols new file mode 100644 index 0000000000000..93115788ad2cf --- /dev/null +++ b/tests/baselines/reference/iteratorVoidResult.symbols @@ -0,0 +1,254 @@ +=== tests/cases/compiler/iteratorVoidResult.ts === +// @strict + +// +// Iterators with 'void' +// + +const o1 = { +>o1 : Symbol(o1, Decl(iteratorVoidResult.ts, 6, 5)) + + [Symbol.iterator]() { +>[Symbol.iterator] : Symbol([Symbol.iterator], Decl(iteratorVoidResult.ts, 6, 12)) +>Symbol.iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --)) +>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --)) +>iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --)) + + return { + next(): IteratorResult { +>next : Symbol(next, Decl(iteratorVoidResult.ts, 8, 16)) +>IteratorResult : Symbol(IteratorResult, Decl(lib.es2015.iterable.d.ts, --, --)) + + return { done: true }; +>done : Symbol(done, Decl(iteratorVoidResult.ts, 10, 24)) + } + }; + } +}; + +// should still be iterable +for (const _ of o1) {} +>_ : Symbol(_, Decl(iteratorVoidResult.ts, 17, 10)) +>o1 : Symbol(o1, Decl(iteratorVoidResult.ts, 6, 5)) + +// should still be spreadable +const a1 = [...o1]; +>a1 : Symbol(a1, Decl(iteratorVoidResult.ts, 20, 5)) +>o1 : Symbol(o1, Decl(iteratorVoidResult.ts, 6, 5)) + +// should still destructure +const [e1] = o1; +>e1 : Symbol(e1, Decl(iteratorVoidResult.ts, 23, 7)) +>o1 : Symbol(o1, Decl(iteratorVoidResult.ts, 6, 5)) + +// verify value of r1 +const r1 = o1[Symbol.iterator]().next(); +>r1 : Symbol(r1, Decl(iteratorVoidResult.ts, 26, 5)) +>o1[Symbol.iterator]().next : Symbol(next, Decl(iteratorVoidResult.ts, 8, 16)) +>o1 : Symbol(o1, Decl(iteratorVoidResult.ts, 6, 5)) +>Symbol.iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --)) +>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --)) +>iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --)) +>next : Symbol(next, Decl(iteratorVoidResult.ts, 8, 16)) + +if (r1.done) r1.value; +>r1.done : Symbol(done, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --)) +>r1 : Symbol(r1, Decl(iteratorVoidResult.ts, 26, 5)) +>done : Symbol(done, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --)) +>r1.value : Symbol(value, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --)) +>r1 : Symbol(r1, Decl(iteratorVoidResult.ts, 26, 5)) +>value : Symbol(value, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --)) + +(function* () { + // verify result of yield* + const x1 = yield * o1; +>x1 : Symbol(x1, Decl(iteratorVoidResult.ts, 31, 9)) +>o1 : Symbol(o1, Decl(iteratorVoidResult.ts, 6, 5)) + +}); + +const o2 = { +>o2 : Symbol(o2, Decl(iteratorVoidResult.ts, 34, 5)) + + [Symbol.iterator]() { +>[Symbol.iterator] : Symbol([Symbol.iterator], Decl(iteratorVoidResult.ts, 34, 12)) +>Symbol.iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --)) +>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --)) +>iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --)) + + return { + next(): IteratorResult { +>next : Symbol(next, Decl(iteratorVoidResult.ts, 36, 16)) +>IteratorResult : Symbol(IteratorResult, Decl(lib.es2015.iterable.d.ts, --, --)) + + return { done: true }; +>done : Symbol(done, Decl(iteratorVoidResult.ts, 38, 24)) + } + }; + } +}; + +// should still be iterable +for (const _ of o2) {} +>_ : Symbol(_, Decl(iteratorVoidResult.ts, 45, 10)) +>o2 : Symbol(o2, Decl(iteratorVoidResult.ts, 34, 5)) + +// should still be spreadable +const a2 = [...o2]; +>a2 : Symbol(a2, Decl(iteratorVoidResult.ts, 48, 5)) +>o2 : Symbol(o2, Decl(iteratorVoidResult.ts, 34, 5)) + +// should still destructure +const [e2] = o2; +>e2 : Symbol(e2, Decl(iteratorVoidResult.ts, 51, 7)) +>o2 : Symbol(o2, Decl(iteratorVoidResult.ts, 34, 5)) + +// verify value of r2 +const r2 = o2[Symbol.iterator]().next(); +>r2 : Symbol(r2, Decl(iteratorVoidResult.ts, 54, 5)) +>o2[Symbol.iterator]().next : Symbol(next, Decl(iteratorVoidResult.ts, 36, 16)) +>o2 : Symbol(o2, Decl(iteratorVoidResult.ts, 34, 5)) +>Symbol.iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --)) +>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --)) +>iterator : Symbol(SymbolConstructor.iterator, Decl(lib.es2015.iterable.d.ts, --, --)) +>next : Symbol(next, Decl(iteratorVoidResult.ts, 36, 16)) + +if (r2.done) r2.value; +>r2.done : Symbol(done, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --)) +>r2 : Symbol(r2, Decl(iteratorVoidResult.ts, 54, 5)) +>done : Symbol(done, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --)) +>r2.value : Symbol(value, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --)) +>r2 : Symbol(r2, Decl(iteratorVoidResult.ts, 54, 5)) +>value : Symbol(value, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --)) + +(function* () { + // verify result of yield* + const x2 = yield * o2; +>x2 : Symbol(x2, Decl(iteratorVoidResult.ts, 59, 9)) +>o2 : Symbol(o2, Decl(iteratorVoidResult.ts, 34, 5)) + +}); + +// +// AsyncIterators with 'void' +// + +async function main() { +>main : Symbol(main, Decl(iteratorVoidResult.ts, 60, 3)) + + // should still be iterable + for await (const _ of o1) {} +>_ : Symbol(_, Decl(iteratorVoidResult.ts, 68, 20)) +>o1 : Symbol(o1, Decl(iteratorVoidResult.ts, 6, 5)) + + for await (const _ of o2) {} +>_ : Symbol(_, Decl(iteratorVoidResult.ts, 69, 20)) +>o2 : Symbol(o2, Decl(iteratorVoidResult.ts, 34, 5)) + + const o3 = { +>o3 : Symbol(o3, Decl(iteratorVoidResult.ts, 71, 9)) + + [Symbol.asyncIterator]() { +>[Symbol.asyncIterator] : Symbol([Symbol.asyncIterator], Decl(iteratorVoidResult.ts, 71, 16)) +>Symbol.asyncIterator : Symbol(SymbolConstructor.asyncIterator, Decl(lib.es2018.asynciterable.d.ts, --, --)) +>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --)) +>asyncIterator : Symbol(SymbolConstructor.asyncIterator, Decl(lib.es2018.asynciterable.d.ts, --, --)) + + return { + async next(): Promise> { +>next : Symbol(next, Decl(iteratorVoidResult.ts, 73, 20)) +>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, --, --)) +>IteratorResult : Symbol(IteratorResult, Decl(lib.es2015.iterable.d.ts, --, --)) + + return { done: true }; +>done : Symbol(done, Decl(iteratorVoidResult.ts, 75, 28)) + } + }; + } + }; + + // should still be iterable + for await (const _ of o3) {} +>_ : Symbol(_, Decl(iteratorVoidResult.ts, 82, 20)) +>o3 : Symbol(o3, Decl(iteratorVoidResult.ts, 71, 9)) + + // verify value of r3 + const r3 = await o3[Symbol.asyncIterator]().next(); +>r3 : Symbol(r3, Decl(iteratorVoidResult.ts, 85, 9)) +>o3[Symbol.asyncIterator]().next : Symbol(next, Decl(iteratorVoidResult.ts, 73, 20)) +>o3 : Symbol(o3, Decl(iteratorVoidResult.ts, 71, 9)) +>Symbol.asyncIterator : Symbol(SymbolConstructor.asyncIterator, Decl(lib.es2018.asynciterable.d.ts, --, --)) +>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --)) +>asyncIterator : Symbol(SymbolConstructor.asyncIterator, Decl(lib.es2018.asynciterable.d.ts, --, --)) +>next : Symbol(next, Decl(iteratorVoidResult.ts, 73, 20)) + + if (r3.done) r3.value; +>r3.done : Symbol(done, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --)) +>r3 : Symbol(r3, Decl(iteratorVoidResult.ts, 85, 9)) +>done : Symbol(done, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --)) +>r3.value : Symbol(value, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --)) +>r3 : Symbol(r3, Decl(iteratorVoidResult.ts, 85, 9)) +>value : Symbol(value, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --)) + + (async function* () { + // verify result of yield* + const x1 = yield * o3; +>x1 : Symbol(x1, Decl(iteratorVoidResult.ts, 90, 13)) +>o3 : Symbol(o3, Decl(iteratorVoidResult.ts, 71, 9)) + + }); + + const o4 = { +>o4 : Symbol(o4, Decl(iteratorVoidResult.ts, 93, 9)) + + [Symbol.asyncIterator]() { +>[Symbol.asyncIterator] : Symbol([Symbol.asyncIterator], Decl(iteratorVoidResult.ts, 93, 16)) +>Symbol.asyncIterator : Symbol(SymbolConstructor.asyncIterator, Decl(lib.es2018.asynciterable.d.ts, --, --)) +>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --)) +>asyncIterator : Symbol(SymbolConstructor.asyncIterator, Decl(lib.es2018.asynciterable.d.ts, --, --)) + + return { + async next(): Promise> { +>next : Symbol(next, Decl(iteratorVoidResult.ts, 95, 20)) +>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, --, --)) +>IteratorResult : Symbol(IteratorResult, Decl(lib.es2015.iterable.d.ts, --, --)) + + return { done: true }; +>done : Symbol(done, Decl(iteratorVoidResult.ts, 97, 28)) + } + }; + } + }; + + // should still be iterable + for await (const _ of o4) {} +>_ : Symbol(_, Decl(iteratorVoidResult.ts, 104, 20)) +>o4 : Symbol(o4, Decl(iteratorVoidResult.ts, 93, 9)) + + // verify value of r4 + const r4 = await o4[Symbol.asyncIterator]().next(); +>r4 : Symbol(r4, Decl(iteratorVoidResult.ts, 107, 9)) +>o4[Symbol.asyncIterator]().next : Symbol(next, Decl(iteratorVoidResult.ts, 95, 20)) +>o4 : Symbol(o4, Decl(iteratorVoidResult.ts, 93, 9)) +>Symbol.asyncIterator : Symbol(SymbolConstructor.asyncIterator, Decl(lib.es2018.asynciterable.d.ts, --, --)) +>Symbol : Symbol(Symbol, Decl(lib.es5.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2019.symbol.d.ts, --, --)) +>asyncIterator : Symbol(SymbolConstructor.asyncIterator, Decl(lib.es2018.asynciterable.d.ts, --, --)) +>next : Symbol(next, Decl(iteratorVoidResult.ts, 95, 20)) + + if (r4.done) r4.value; +>r4.done : Symbol(done, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --)) +>r4 : Symbol(r4, Decl(iteratorVoidResult.ts, 107, 9)) +>done : Symbol(done, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --)) +>r4.value : Symbol(value, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --)) +>r4 : Symbol(r4, Decl(iteratorVoidResult.ts, 107, 9)) +>value : Symbol(value, Decl(lib.es2015.iterable.d.ts, --, --), Decl(lib.es2015.iterable.d.ts, --, --)) + + (async function* () { + // verify result of yield* + const x4 = yield * o4; +>x4 : Symbol(x4, Decl(iteratorVoidResult.ts, 112, 13)) +>o4 : Symbol(o4, Decl(iteratorVoidResult.ts, 93, 9)) + + }); +} + diff --git a/tests/baselines/reference/iteratorVoidResult.types b/tests/baselines/reference/iteratorVoidResult.types new file mode 100644 index 0000000000000..4eb4c5880eb4e --- /dev/null +++ b/tests/baselines/reference/iteratorVoidResult.types @@ -0,0 +1,302 @@ +=== tests/cases/compiler/iteratorVoidResult.ts === +// @strict + +// +// Iterators with 'void' +// + +const o1 = { +>o1 : { [Symbol.iterator](): { next(): IteratorResult; }; } +>{ [Symbol.iterator]() { return { next(): IteratorResult { return { done: true }; } }; }} : { [Symbol.iterator](): { next(): IteratorResult; }; } + + [Symbol.iterator]() { +>[Symbol.iterator] : () => { next(): IteratorResult; } +>Symbol.iterator : symbol +>Symbol : SymbolConstructor +>iterator : symbol + + return { +>{ next(): IteratorResult { return { done: true }; } } : { next(): IteratorResult; } + + next(): IteratorResult { +>next : () => IteratorResult + + return { done: true }; +>{ done: true } : { done: true; } +>done : true +>true : true + } + }; + } +}; + +// should still be iterable +for (const _ of o1) {} +>_ : number +>o1 : { [Symbol.iterator](): { next(): IteratorResult; }; } + +// should still be spreadable +const a1 = [...o1]; +>a1 : number[] +>[...o1] : number[] +>...o1 : number +>o1 : { [Symbol.iterator](): { next(): IteratorResult; }; } + +// should still destructure +const [e1] = o1; +>e1 : number +>o1 : { [Symbol.iterator](): { next(): IteratorResult; }; } + +// verify value of r1 +const r1 = o1[Symbol.iterator]().next(); +>r1 : IteratorResult +>o1[Symbol.iterator]().next() : IteratorResult +>o1[Symbol.iterator]().next : () => IteratorResult +>o1[Symbol.iterator]() : { next(): IteratorResult; } +>o1[Symbol.iterator] : () => { next(): IteratorResult; } +>o1 : { [Symbol.iterator](): { next(): IteratorResult; }; } +>Symbol.iterator : symbol +>Symbol : SymbolConstructor +>iterator : symbol +>next : () => IteratorResult + +if (r1.done) r1.value; +>r1.done : boolean +>r1 : IteratorResult +>done : boolean +>r1.value : void +>r1 : IteratorVoidReturnResult | IteratorReturnResult +>value : void + +(function* () { +>(function* () { // verify result of yield* const x1 = yield * o1;}) : () => Generator +>function* () { // verify result of yield* const x1 = yield * o1;} : () => Generator + + // verify result of yield* + const x1 = yield * o1; +>x1 : void +>yield * o1 : void +>o1 : { [Symbol.iterator](): { next(): IteratorResult; }; } + +}); + +const o2 = { +>o2 : { [Symbol.iterator](): { next(): IteratorResult; }; } +>{ [Symbol.iterator]() { return { next(): IteratorResult { return { done: true }; } }; }} : { [Symbol.iterator](): { next(): IteratorResult; }; } + + [Symbol.iterator]() { +>[Symbol.iterator] : () => { next(): IteratorResult; } +>Symbol.iterator : symbol +>Symbol : SymbolConstructor +>iterator : symbol + + return { +>{ next(): IteratorResult { return { done: true }; } } : { next(): IteratorResult; } + + next(): IteratorResult { +>next : () => IteratorResult + + return { done: true }; +>{ done: true } : { done: true; } +>done : true +>true : true + } + }; + } +}; + +// should still be iterable +for (const _ of o2) {} +>_ : number +>o2 : { [Symbol.iterator](): { next(): IteratorResult; }; } + +// should still be spreadable +const a2 = [...o2]; +>a2 : number[] +>[...o2] : number[] +>...o2 : number +>o2 : { [Symbol.iterator](): { next(): IteratorResult; }; } + +// should still destructure +const [e2] = o2; +>e2 : number +>o2 : { [Symbol.iterator](): { next(): IteratorResult; }; } + +// verify value of r2 +const r2 = o2[Symbol.iterator]().next(); +>r2 : IteratorResult +>o2[Symbol.iterator]().next() : IteratorResult +>o2[Symbol.iterator]().next : () => IteratorResult +>o2[Symbol.iterator]() : { next(): IteratorResult; } +>o2[Symbol.iterator] : () => { next(): IteratorResult; } +>o2 : { [Symbol.iterator](): { next(): IteratorResult; }; } +>Symbol.iterator : symbol +>Symbol : SymbolConstructor +>iterator : symbol +>next : () => IteratorResult + +if (r2.done) r2.value; +>r2.done : boolean +>r2 : IteratorResult +>done : boolean +>r2.value : number | void +>r2 : IteratorVoidReturnResult | IteratorReturnResult +>value : number | void + +(function* () { +>(function* () { // verify result of yield* const x2 = yield * o2;}) : () => Generator +>function* () { // verify result of yield* const x2 = yield * o2;} : () => Generator + + // verify result of yield* + const x2 = yield * o2; +>x2 : number | void +>yield * o2 : number | void +>o2 : { [Symbol.iterator](): { next(): IteratorResult; }; } + +}); + +// +// AsyncIterators with 'void' +// + +async function main() { +>main : () => Promise + + // should still be iterable + for await (const _ of o1) {} +>_ : number +>o1 : { [Symbol.iterator](): { next(): IteratorResult; }; } + + for await (const _ of o2) {} +>_ : number +>o2 : { [Symbol.iterator](): { next(): IteratorResult; }; } + + const o3 = { +>o3 : { [Symbol.asyncIterator](): { next(): Promise>; }; } +>{ [Symbol.asyncIterator]() { return { async next(): Promise> { return { done: true }; } }; } } : { [Symbol.asyncIterator](): { next(): Promise>; }; } + + [Symbol.asyncIterator]() { +>[Symbol.asyncIterator] : () => { next(): Promise>; } +>Symbol.asyncIterator : symbol +>Symbol : SymbolConstructor +>asyncIterator : symbol + + return { +>{ async next(): Promise> { return { done: true }; } } : { next(): Promise>; } + + async next(): Promise> { +>next : () => Promise> + + return { done: true }; +>{ done: true } : { done: true; } +>done : true +>true : true + } + }; + } + }; + + // should still be iterable + for await (const _ of o3) {} +>_ : number +>o3 : { [Symbol.asyncIterator](): { next(): Promise>; }; } + + // verify value of r3 + const r3 = await o3[Symbol.asyncIterator]().next(); +>r3 : IteratorResult +>await o3[Symbol.asyncIterator]().next() : IteratorResult +>o3[Symbol.asyncIterator]().next() : Promise> +>o3[Symbol.asyncIterator]().next : () => Promise> +>o3[Symbol.asyncIterator]() : { next(): Promise>; } +>o3[Symbol.asyncIterator] : () => { next(): Promise>; } +>o3 : { [Symbol.asyncIterator](): { next(): Promise>; }; } +>Symbol.asyncIterator : symbol +>Symbol : SymbolConstructor +>asyncIterator : symbol +>next : () => Promise> + + if (r3.done) r3.value; +>r3.done : boolean +>r3 : IteratorResult +>done : boolean +>r3.value : void +>r3 : IteratorVoidReturnResult | IteratorReturnResult +>value : void + + (async function* () { +>(async function* () { // verify result of yield* const x1 = yield * o3; }) : () => AsyncGenerator +>async function* () { // verify result of yield* const x1 = yield * o3; } : () => AsyncGenerator + + // verify result of yield* + const x1 = yield * o3; +>x1 : void +>yield * o3 : void +>o3 : { [Symbol.asyncIterator](): { next(): Promise>; }; } + + }); + + const o4 = { +>o4 : { [Symbol.asyncIterator](): { next(): Promise>; }; } +>{ [Symbol.asyncIterator]() { return { async next(): Promise> { return { done: true }; } }; } } : { [Symbol.asyncIterator](): { next(): Promise>; }; } + + [Symbol.asyncIterator]() { +>[Symbol.asyncIterator] : () => { next(): Promise>; } +>Symbol.asyncIterator : symbol +>Symbol : SymbolConstructor +>asyncIterator : symbol + + return { +>{ async next(): Promise> { return { done: true }; } } : { next(): Promise>; } + + async next(): Promise> { +>next : () => Promise> + + return { done: true }; +>{ done: true } : { done: true; } +>done : true +>true : true + } + }; + } + }; + + // should still be iterable + for await (const _ of o4) {} +>_ : number +>o4 : { [Symbol.asyncIterator](): { next(): Promise>; }; } + + // verify value of r4 + const r4 = await o4[Symbol.asyncIterator]().next(); +>r4 : IteratorResult +>await o4[Symbol.asyncIterator]().next() : IteratorResult +>o4[Symbol.asyncIterator]().next() : Promise> +>o4[Symbol.asyncIterator]().next : () => Promise> +>o4[Symbol.asyncIterator]() : { next(): Promise>; } +>o4[Symbol.asyncIterator] : () => { next(): Promise>; } +>o4 : { [Symbol.asyncIterator](): { next(): Promise>; }; } +>Symbol.asyncIterator : symbol +>Symbol : SymbolConstructor +>asyncIterator : symbol +>next : () => Promise> + + if (r4.done) r4.value; +>r4.done : boolean +>r4 : IteratorResult +>done : boolean +>r4.value : number | void +>r4 : IteratorVoidReturnResult | IteratorReturnResult +>value : number | void + + (async function* () { +>(async function* () { // verify result of yield* const x4 = yield * o4; }) : () => AsyncGenerator +>async function* () { // verify result of yield* const x4 = yield * o4; } : () => AsyncGenerator + + // verify result of yield* + const x4 = yield * o4; +>x4 : number | void +>yield * o4 : number | void +>o4 : { [Symbol.asyncIterator](): { next(): Promise>; }; } + + }); +} + diff --git a/tests/baselines/reference/types.asyncGenerators.es2018.2.errors.txt b/tests/baselines/reference/types.asyncGenerators.es2018.2.errors.txt index 6f3a7581e64bf..87970c8250b5d 100644 --- a/tests/baselines/reference/types.asyncGenerators.es2018.2.errors.txt +++ b/tests/baselines/reference/types.asyncGenerators.es2018.2.errors.txt @@ -177,13 +177,13 @@ tests/cases/conformance/types/asyncGenerators/types.asyncGenerators.es2018.2.ts( async function * explicitReturnType10(): IterableIterator { ~~~~~~~~~~~~~~~~~~~~~~~~ !!! error TS2741: Property '[Symbol.iterator]' is missing in type 'AsyncGenerator' but required in type 'IterableIterator'. -!!! related TS2728 /.ts/lib.es2015.iterable.d.ts:55:5: '[Symbol.iterator]' is declared here. +!!! related TS2728 /.ts/lib.es2015.iterable.d.ts:63:5: '[Symbol.iterator]' is declared here. yield 1; } async function * explicitReturnType11(): Iterable { ~~~~~~~~~~~~~~~~ !!! error TS2741: Property '[Symbol.iterator]' is missing in type 'AsyncGenerator' but required in type 'Iterable'. -!!! related TS2728 /.ts/lib.es2015.iterable.d.ts:51:5: '[Symbol.iterator]' is declared here. +!!! related TS2728 /.ts/lib.es2015.iterable.d.ts:59:5: '[Symbol.iterator]' is declared here. yield 1; } async function * explicitReturnType12(): Iterator { diff --git a/tests/cases/compiler/iteratorVoidResult.ts b/tests/cases/compiler/iteratorVoidResult.ts new file mode 100644 index 0000000000000..d060591fd913b --- /dev/null +++ b/tests/cases/compiler/iteratorVoidResult.ts @@ -0,0 +1,117 @@ +// @strict +// @target: esnext +// @noEmit: true + +// +// Iterators with 'void' +// + +const o1 = { + [Symbol.iterator]() { + return { + next(): IteratorResult { + return { done: true }; + } + }; + } +}; + +// should still be iterable +for (const _ of o1) {} + +// should still be spreadable +const a1 = [...o1]; + +// should still destructure +const [e1] = o1; + +// verify value of r1 +const r1 = o1[Symbol.iterator]().next(); +if (r1.done) r1.value; + +(function* () { + // verify result of yield* + const x1 = yield * o1; +}); + +const o2 = { + [Symbol.iterator]() { + return { + next(): IteratorResult { + return { done: true }; + } + }; + } +}; + +// should still be iterable +for (const _ of o2) {} + +// should still be spreadable +const a2 = [...o2]; + +// should still destructure +const [e2] = o2; + +// verify value of r2 +const r2 = o2[Symbol.iterator]().next(); +if (r2.done) r2.value; + +(function* () { + // verify result of yield* + const x2 = yield * o2; +}); + +// +// AsyncIterators with 'void' +// + +async function main() { + // should still be iterable + for await (const _ of o1) {} + for await (const _ of o2) {} + + const o3 = { + [Symbol.asyncIterator]() { + return { + async next(): Promise> { + return { done: true }; + } + }; + } + }; + + // should still be iterable + for await (const _ of o3) {} + + // verify value of r3 + const r3 = await o3[Symbol.asyncIterator]().next(); + if (r3.done) r3.value; + + (async function* () { + // verify result of yield* + const x1 = yield * o3; + }); + + const o4 = { + [Symbol.asyncIterator]() { + return { + async next(): Promise> { + return { done: true }; + } + }; + } + }; + + // should still be iterable + for await (const _ of o4) {} + + // verify value of r4 + const r4 = await o4[Symbol.asyncIterator]().next(); + if (r4.done) r4.value; + + (async function* () { + // verify result of yield* + const x4 = yield * o4; + }); +}