mirror of
https://github.com/microsoft/TypeScript.git
synced 2026-05-15 21:36:50 -05:00
A union including non-iterable types is not iterable (#40350)
* WIP * If method type derives solely from the global iterator or generator type, use its type arguments * Add test for problem fixed as side effect
This commit is contained in:
@@ -33881,8 +33881,9 @@ namespace ts {
|
||||
if (iterationTypes === noIterationTypes) {
|
||||
if (errorNode) {
|
||||
reportTypeNotIterableError(errorNode, type, !!(use & IterationUse.AllowsAsyncIterablesFlag));
|
||||
errorNode = undefined;
|
||||
}
|
||||
setCachedIterationTypes(type, cacheKey, noIterationTypes);
|
||||
return undefined;
|
||||
}
|
||||
else {
|
||||
allIterationTypes = append(allIterationTypes, iterationTypes);
|
||||
@@ -34224,6 +34225,28 @@ namespace ts {
|
||||
return methodName === "next" ? anyIterationTypes : undefined;
|
||||
}
|
||||
|
||||
// If the method signature comes exclusively from the global iterator or generator type,
|
||||
// create iteration types from its type arguments like `getIterationTypesOfIteratorFast`
|
||||
// does (so as to remove `undefined` from the next and return types). We arrive here when
|
||||
// a contextual type for a generator was not a direct reference to one of those global types,
|
||||
// but looking up `methodType` referred to one of them (and nothing else). E.g., in
|
||||
// `interface SpecialIterator extends Iterator<number> {}`, `SpecialIterator` is not a
|
||||
// reference to `Iterator`, but its `next` member derives exclusively from `Iterator`.
|
||||
if (methodType?.symbol && methodSignatures.length === 1) {
|
||||
const globalGeneratorType = resolver.getGlobalGeneratorType(/*reportErrors*/ false);
|
||||
const globalIteratorType = resolver.getGlobalIteratorType(/*reportErrors*/ false);
|
||||
const isGeneratorMethod = globalGeneratorType.symbol?.members?.get(methodName as __String) === methodType.symbol;
|
||||
const isIteratorMethod = !isGeneratorMethod && globalIteratorType.symbol?.members?.get(methodName as __String) === methodType.symbol;
|
||||
if (isGeneratorMethod || isIteratorMethod) {
|
||||
const globalType = isGeneratorMethod ? globalGeneratorType : globalIteratorType;
|
||||
const { mapper } = methodType as AnonymousType;
|
||||
return createIterationTypes(
|
||||
getMappedType(globalType.typeParameters![0], mapper!),
|
||||
getMappedType(globalType.typeParameters![1], mapper!),
|
||||
methodName === "next" ? getMappedType(globalType.typeParameters![2], mapper!) : undefined);
|
||||
}
|
||||
}
|
||||
|
||||
// Extract the first parameter and return type of each signature.
|
||||
let methodParameterTypes: Type[] | undefined;
|
||||
let methodReturnTypes: Type[] | undefined;
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
tests/cases/conformance/es6/destructuring/destructuringArrayBindingPatternAndAssignment4.ts(5,7): error TS2548: Type 'number[] | null' is not an array type or does not have a '[Symbol.iterator]()' method that returns an iterator.
|
||||
|
||||
|
||||
==== tests/cases/conformance/es6/destructuring/destructuringArrayBindingPatternAndAssignment4.ts (1 errors) ====
|
||||
// #35497
|
||||
|
||||
|
||||
declare const data: number[] | null;
|
||||
const [value] = data; // Error
|
||||
~~~~~~~
|
||||
!!! error TS2548: Type 'number[] | null' is not an array type or does not have a '[Symbol.iterator]()' method that returns an iterator.
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
//// [destructuringArrayBindingPatternAndAssignment4.ts]
|
||||
// #35497
|
||||
|
||||
|
||||
declare const data: number[] | null;
|
||||
const [value] = data; // Error
|
||||
|
||||
|
||||
//// [destructuringArrayBindingPatternAndAssignment4.js]
|
||||
"use strict";
|
||||
// #35497
|
||||
var __read = (this && this.__read) || function (o, n) {
|
||||
var m = typeof Symbol === "function" && o[Symbol.iterator];
|
||||
if (!m) return o;
|
||||
var i = m.call(o), r, ar = [], e;
|
||||
try {
|
||||
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
|
||||
}
|
||||
catch (error) { e = { error: error }; }
|
||||
finally {
|
||||
try {
|
||||
if (r && !r.done && (m = i["return"])) m.call(i);
|
||||
}
|
||||
finally { if (e) throw e.error; }
|
||||
}
|
||||
return ar;
|
||||
};
|
||||
var _a = __read(data, 1), value = _a[0]; // Error
|
||||
@@ -0,0 +1,11 @@
|
||||
=== tests/cases/conformance/es6/destructuring/destructuringArrayBindingPatternAndAssignment4.ts ===
|
||||
// #35497
|
||||
|
||||
|
||||
declare const data: number[] | null;
|
||||
>data : Symbol(data, Decl(destructuringArrayBindingPatternAndAssignment4.ts, 3, 13))
|
||||
|
||||
const [value] = data; // Error
|
||||
>value : Symbol(value, Decl(destructuringArrayBindingPatternAndAssignment4.ts, 4, 7))
|
||||
>data : Symbol(data, Decl(destructuringArrayBindingPatternAndAssignment4.ts, 3, 13))
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
=== tests/cases/conformance/es6/destructuring/destructuringArrayBindingPatternAndAssignment4.ts ===
|
||||
// #35497
|
||||
|
||||
|
||||
declare const data: number[] | null;
|
||||
>data : number[] | null
|
||||
>null : null
|
||||
|
||||
const [value] = data; // Error
|
||||
>value : any
|
||||
>data : number[] | null
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
//// [generatorReturnTypeIndirectReferenceToGlobalType.ts]
|
||||
interface I1 extends Iterator<0, 1, 2> {}
|
||||
|
||||
function* f1(): I1 {
|
||||
const a = yield 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
//// [generatorReturnTypeIndirectReferenceToGlobalType.js]
|
||||
"use strict";
|
||||
function* f1() {
|
||||
const a = yield 0;
|
||||
return 1;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
=== tests/cases/conformance/generators/generatorReturnTypeIndirectReferenceToGlobalType.ts ===
|
||||
interface I1 extends Iterator<0, 1, 2> {}
|
||||
>I1 : Symbol(I1, Decl(generatorReturnTypeIndirectReferenceToGlobalType.ts, 0, 0))
|
||||
>Iterator : Symbol(Iterator, Decl(lib.es2015.iterable.d.ts, --, --))
|
||||
|
||||
function* f1(): I1 {
|
||||
>f1 : Symbol(f1, Decl(generatorReturnTypeIndirectReferenceToGlobalType.ts, 0, 41))
|
||||
>I1 : Symbol(I1, Decl(generatorReturnTypeIndirectReferenceToGlobalType.ts, 0, 0))
|
||||
|
||||
const a = yield 0;
|
||||
>a : Symbol(a, Decl(generatorReturnTypeIndirectReferenceToGlobalType.ts, 3, 7))
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
=== tests/cases/conformance/generators/generatorReturnTypeIndirectReferenceToGlobalType.ts ===
|
||||
interface I1 extends Iterator<0, 1, 2> {}
|
||||
|
||||
function* f1(): I1 {
|
||||
>f1 : () => I1
|
||||
|
||||
const a = yield 0;
|
||||
>a : 2
|
||||
>yield 0 : 2
|
||||
>0 : 0
|
||||
|
||||
return 1;
|
||||
>1 : 1
|
||||
}
|
||||
|
||||
@@ -25,11 +25,11 @@ declare function f2<T, R, S>(gen: () => Generator<R, T, S> | AsyncGenerator<R, T
|
||||
f2<0, 0, 1>(async function* () {
|
||||
>f2<0, 0, 1>(async function* () { const a = yield 0; return 0;}) : void
|
||||
>f2 : <T, R, S>(gen: () => Generator<R, T, S> | AsyncGenerator<R, T, S>) => void
|
||||
>async function* () { const a = yield 0; return 0;} : () => AsyncGenerator<0, 0, 1>
|
||||
>async function* () { const a = yield 0; return 0;} : () => AsyncGenerator<0, 0, 1 | undefined>
|
||||
|
||||
const a = yield 0;
|
||||
>a : 1
|
||||
>yield 0 : 1
|
||||
>a : 1 | undefined
|
||||
>yield 0 : 1 | undefined
|
||||
>0 : 0
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -44,7 +44,7 @@ tests/cases/conformance/types/asyncGenerators/types.asyncGenerators.es2018.2.ts(
|
||||
tests/cases/conformance/types/asyncGenerators/types.asyncGenerators.es2018.2.ts(70,42): error TS2322: Type 'AsyncGenerator<number, any, undefined>' is not assignable to type 'Iterator<number, any, undefined>'.
|
||||
The types returned by 'next(...)' are incompatible between these types.
|
||||
Type 'Promise<IteratorResult<number, any>>' is not assignable to type 'IteratorResult<number, any>'.
|
||||
Property 'value' is missing in type 'Promise<IteratorResult<number, any>>' but required in type 'IteratorYieldResult<number>'.
|
||||
Type 'Promise<IteratorResult<number, any>>' is missing the following properties from type 'IteratorReturnResult<any>': done, value
|
||||
tests/cases/conformance/types/asyncGenerators/types.asyncGenerators.es2018.2.ts(74,12): error TS2504: Type '{}' must have a '[Symbol.asyncIterator]()' method that returns an async iterator.
|
||||
|
||||
|
||||
@@ -191,8 +191,7 @@ tests/cases/conformance/types/asyncGenerators/types.asyncGenerators.es2018.2.ts(
|
||||
!!! error TS2322: Type 'AsyncGenerator<number, any, undefined>' is not assignable to type 'Iterator<number, any, undefined>'.
|
||||
!!! error TS2322: The types returned by 'next(...)' are incompatible between these types.
|
||||
!!! error TS2322: Type 'Promise<IteratorResult<number, any>>' is not assignable to type 'IteratorResult<number, any>'.
|
||||
!!! error TS2322: Property 'value' is missing in type 'Promise<IteratorResult<number, any>>' but required in type 'IteratorYieldResult<number>'.
|
||||
!!! related TS2728 /.ts/lib.es2015.iterable.d.ts:33:5: 'value' is declared here.
|
||||
!!! error TS2322: Type 'Promise<IteratorResult<number, any>>' is missing the following properties from type 'IteratorReturnResult<any>': done, value
|
||||
yield 1;
|
||||
}
|
||||
async function * yieldStar() {
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// #35497
|
||||
|
||||
// @target: es5
|
||||
// @downlevelIteration: true
|
||||
// @lib: es6
|
||||
// @strict: true
|
||||
|
||||
declare const data: number[] | null;
|
||||
const [value] = data; // Error
|
||||
@@ -0,0 +1,9 @@
|
||||
// @strict: true
|
||||
// @target: esnext
|
||||
|
||||
interface I1 extends Iterator<0, 1, 2> {}
|
||||
|
||||
function* f1(): I1 {
|
||||
const a = yield 0;
|
||||
return 1;
|
||||
}
|
||||
Reference in New Issue
Block a user