Compare commits

...

1 commit

Author SHA1 Message Date
Ron Buckton dad88fc53e Add IteratorVoidReturnResult for optional 'value' when done 2020-09-28 19:37:06 -07:00
6 changed files with 692 additions and 3 deletions

View file

@ -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 && <GenericType>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);

View file

@ -18,7 +18,15 @@ interface IteratorReturnResult<TReturn> {
value: TReturn;
}
type IteratorResult<T, TReturn = any> = IteratorYieldResult<T> | IteratorReturnResult<TReturn>;
interface IteratorVoidReturnResult {
done: true;
value?: void;
}
type IteratorResult<T, TReturn = any> =
| IteratorYieldResult<T>
| IteratorReturnResult<TReturn>
| (TReturn extends void ? IteratorVoidReturnResult : never);
interface Iterator<T, TReturn = any, TNext = undefined> {
// NOTE: 'next' is defined using a tuple to ensure we report the correct assignability errors in all places.

View file

@ -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<number, void> {
>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<number, number | void> {
>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<IteratorResult<number, void>> {
>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<IteratorResult<number, number | void>> {
>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))
});
}

View file

@ -0,0 +1,302 @@
=== tests/cases/compiler/iteratorVoidResult.ts ===
// @strict
//
// Iterators with 'void'
//
const o1 = {
>o1 : { [Symbol.iterator](): { next(): IteratorResult<number, void>; }; }
>{ [Symbol.iterator]() { return { next(): IteratorResult<number, void> { return { done: true }; } }; }} : { [Symbol.iterator](): { next(): IteratorResult<number, void>; }; }
[Symbol.iterator]() {
>[Symbol.iterator] : () => { next(): IteratorResult<number, void>; }
>Symbol.iterator : symbol
>Symbol : SymbolConstructor
>iterator : symbol
return {
>{ next(): IteratorResult<number, void> { return { done: true }; } } : { next(): IteratorResult<number, void>; }
next(): IteratorResult<number, void> {
>next : () => IteratorResult<number, void>
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<number, void>; }; }
// should still be spreadable
const a1 = [...o1];
>a1 : number[]
>[...o1] : number[]
>...o1 : number
>o1 : { [Symbol.iterator](): { next(): IteratorResult<number, void>; }; }
// should still destructure
const [e1] = o1;
>e1 : number
>o1 : { [Symbol.iterator](): { next(): IteratorResult<number, void>; }; }
// verify value of r1
const r1 = o1[Symbol.iterator]().next();
>r1 : IteratorResult<number, void>
>o1[Symbol.iterator]().next() : IteratorResult<number, void>
>o1[Symbol.iterator]().next : () => IteratorResult<number, void>
>o1[Symbol.iterator]() : { next(): IteratorResult<number, void>; }
>o1[Symbol.iterator] : () => { next(): IteratorResult<number, void>; }
>o1 : { [Symbol.iterator](): { next(): IteratorResult<number, void>; }; }
>Symbol.iterator : symbol
>Symbol : SymbolConstructor
>iterator : symbol
>next : () => IteratorResult<number, void>
if (r1.done) r1.value;
>r1.done : boolean
>r1 : IteratorResult<number, void>
>done : boolean
>r1.value : void
>r1 : IteratorVoidReturnResult | IteratorReturnResult<void>
>value : void
(function* () {
>(function* () { // verify result of yield* const x1 = yield * o1;}) : () => Generator<number, void, unknown>
>function* () { // verify result of yield* const x1 = yield * o1;} : () => Generator<number, void, unknown>
// verify result of yield*
const x1 = yield * o1;
>x1 : void
>yield * o1 : void
>o1 : { [Symbol.iterator](): { next(): IteratorResult<number, void>; }; }
});
const o2 = {
>o2 : { [Symbol.iterator](): { next(): IteratorResult<number, number | void>; }; }
>{ [Symbol.iterator]() { return { next(): IteratorResult<number, number | void> { return { done: true }; } }; }} : { [Symbol.iterator](): { next(): IteratorResult<number, number | void>; }; }
[Symbol.iterator]() {
>[Symbol.iterator] : () => { next(): IteratorResult<number, number | void>; }
>Symbol.iterator : symbol
>Symbol : SymbolConstructor
>iterator : symbol
return {
>{ next(): IteratorResult<number, number | void> { return { done: true }; } } : { next(): IteratorResult<number, number | void>; }
next(): IteratorResult<number, number | void> {
>next : () => IteratorResult<number, number | void>
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<number, number | void>; }; }
// should still be spreadable
const a2 = [...o2];
>a2 : number[]
>[...o2] : number[]
>...o2 : number
>o2 : { [Symbol.iterator](): { next(): IteratorResult<number, number | void>; }; }
// should still destructure
const [e2] = o2;
>e2 : number
>o2 : { [Symbol.iterator](): { next(): IteratorResult<number, number | void>; }; }
// verify value of r2
const r2 = o2[Symbol.iterator]().next();
>r2 : IteratorResult<number, number | void>
>o2[Symbol.iterator]().next() : IteratorResult<number, number | void>
>o2[Symbol.iterator]().next : () => IteratorResult<number, number | void>
>o2[Symbol.iterator]() : { next(): IteratorResult<number, number | void>; }
>o2[Symbol.iterator] : () => { next(): IteratorResult<number, number | void>; }
>o2 : { [Symbol.iterator](): { next(): IteratorResult<number, number | void>; }; }
>Symbol.iterator : symbol
>Symbol : SymbolConstructor
>iterator : symbol
>next : () => IteratorResult<number, number | void>
if (r2.done) r2.value;
>r2.done : boolean
>r2 : IteratorResult<number, number | void>
>done : boolean
>r2.value : number | void
>r2 : IteratorVoidReturnResult | IteratorReturnResult<number | void>
>value : number | void
(function* () {
>(function* () { // verify result of yield* const x2 = yield * o2;}) : () => Generator<number, void, unknown>
>function* () { // verify result of yield* const x2 = yield * o2;} : () => Generator<number, void, unknown>
// verify result of yield*
const x2 = yield * o2;
>x2 : number | void
>yield * o2 : number | void
>o2 : { [Symbol.iterator](): { next(): IteratorResult<number, number | void>; }; }
});
//
// AsyncIterators with 'void'
//
async function main() {
>main : () => Promise<void>
// should still be iterable
for await (const _ of o1) {}
>_ : number
>o1 : { [Symbol.iterator](): { next(): IteratorResult<number, void>; }; }
for await (const _ of o2) {}
>_ : number
>o2 : { [Symbol.iterator](): { next(): IteratorResult<number, number | void>; }; }
const o3 = {
>o3 : { [Symbol.asyncIterator](): { next(): Promise<IteratorResult<number, void>>; }; }
>{ [Symbol.asyncIterator]() { return { async next(): Promise<IteratorResult<number, void>> { return { done: true }; } }; } } : { [Symbol.asyncIterator](): { next(): Promise<IteratorResult<number, void>>; }; }
[Symbol.asyncIterator]() {
>[Symbol.asyncIterator] : () => { next(): Promise<IteratorResult<number, void>>; }
>Symbol.asyncIterator : symbol
>Symbol : SymbolConstructor
>asyncIterator : symbol
return {
>{ async next(): Promise<IteratorResult<number, void>> { return { done: true }; } } : { next(): Promise<IteratorResult<number, void>>; }
async next(): Promise<IteratorResult<number, void>> {
>next : () => Promise<IteratorResult<number, void>>
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<IteratorResult<number, void>>; }; }
// verify value of r3
const r3 = await o3[Symbol.asyncIterator]().next();
>r3 : IteratorResult<number, void>
>await o3[Symbol.asyncIterator]().next() : IteratorResult<number, void>
>o3[Symbol.asyncIterator]().next() : Promise<IteratorResult<number, void>>
>o3[Symbol.asyncIterator]().next : () => Promise<IteratorResult<number, void>>
>o3[Symbol.asyncIterator]() : { next(): Promise<IteratorResult<number, void>>; }
>o3[Symbol.asyncIterator] : () => { next(): Promise<IteratorResult<number, void>>; }
>o3 : { [Symbol.asyncIterator](): { next(): Promise<IteratorResult<number, void>>; }; }
>Symbol.asyncIterator : symbol
>Symbol : SymbolConstructor
>asyncIterator : symbol
>next : () => Promise<IteratorResult<number, void>>
if (r3.done) r3.value;
>r3.done : boolean
>r3 : IteratorResult<number, void>
>done : boolean
>r3.value : void
>r3 : IteratorVoidReturnResult | IteratorReturnResult<void>
>value : void
(async function* () {
>(async function* () { // verify result of yield* const x1 = yield * o3; }) : () => AsyncGenerator<number, void, unknown>
>async function* () { // verify result of yield* const x1 = yield * o3; } : () => AsyncGenerator<number, void, unknown>
// verify result of yield*
const x1 = yield * o3;
>x1 : void
>yield * o3 : void
>o3 : { [Symbol.asyncIterator](): { next(): Promise<IteratorResult<number, void>>; }; }
});
const o4 = {
>o4 : { [Symbol.asyncIterator](): { next(): Promise<IteratorResult<number, number | void>>; }; }
>{ [Symbol.asyncIterator]() { return { async next(): Promise<IteratorResult<number, number | void>> { return { done: true }; } }; } } : { [Symbol.asyncIterator](): { next(): Promise<IteratorResult<number, number | void>>; }; }
[Symbol.asyncIterator]() {
>[Symbol.asyncIterator] : () => { next(): Promise<IteratorResult<number, number | void>>; }
>Symbol.asyncIterator : symbol
>Symbol : SymbolConstructor
>asyncIterator : symbol
return {
>{ async next(): Promise<IteratorResult<number, number | void>> { return { done: true }; } } : { next(): Promise<IteratorResult<number, number | void>>; }
async next(): Promise<IteratorResult<number, number | void>> {
>next : () => Promise<IteratorResult<number, number | void>>
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<IteratorResult<number, number | void>>; }; }
// verify value of r4
const r4 = await o4[Symbol.asyncIterator]().next();
>r4 : IteratorResult<number, number | void>
>await o4[Symbol.asyncIterator]().next() : IteratorResult<number, number | void>
>o4[Symbol.asyncIterator]().next() : Promise<IteratorResult<number, number | void>>
>o4[Symbol.asyncIterator]().next : () => Promise<IteratorResult<number, number | void>>
>o4[Symbol.asyncIterator]() : { next(): Promise<IteratorResult<number, number | void>>; }
>o4[Symbol.asyncIterator] : () => { next(): Promise<IteratorResult<number, number | void>>; }
>o4 : { [Symbol.asyncIterator](): { next(): Promise<IteratorResult<number, number | void>>; }; }
>Symbol.asyncIterator : symbol
>Symbol : SymbolConstructor
>asyncIterator : symbol
>next : () => Promise<IteratorResult<number, number | void>>
if (r4.done) r4.value;
>r4.done : boolean
>r4 : IteratorResult<number, number | void>
>done : boolean
>r4.value : number | void
>r4 : IteratorVoidReturnResult | IteratorReturnResult<number | void>
>value : number | void
(async function* () {
>(async function* () { // verify result of yield* const x4 = yield * o4; }) : () => AsyncGenerator<number, void, unknown>
>async function* () { // verify result of yield* const x4 = yield * o4; } : () => AsyncGenerator<number, void, unknown>
// verify result of yield*
const x4 = yield * o4;
>x4 : number | void
>yield * o4 : number | void
>o4 : { [Symbol.asyncIterator](): { next(): Promise<IteratorResult<number, number | void>>; }; }
});
}

View file

@ -177,13 +177,13 @@ tests/cases/conformance/types/asyncGenerators/types.asyncGenerators.es2018.2.ts(
async function * explicitReturnType10(): IterableIterator<number> {
~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2741: Property '[Symbol.iterator]' is missing in type 'AsyncGenerator<number, any, undefined>' but required in type 'IterableIterator<number>'.
!!! 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<number> {
~~~~~~~~~~~~~~~~
!!! error TS2741: Property '[Symbol.iterator]' is missing in type 'AsyncGenerator<any, any, any>' but required in type 'Iterable<number>'.
!!! 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<number> {

View file

@ -0,0 +1,117 @@
// @strict
// @target: esnext
// @noEmit: true
//
// Iterators with 'void'
//
const o1 = {
[Symbol.iterator]() {
return {
next(): IteratorResult<number, void> {
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<number, number | void> {
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<IteratorResult<number, void>> {
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<IteratorResult<number, number | void>> {
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;
});
}