From 310c9d841b1923574c023af250e08320751b75ee Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Thu, 30 Aug 2018 13:13:57 -0700 Subject: [PATCH 1/2] Always check index type validity for all types when an error node is present so we always issue an error --- src/compiler/checker.ts | 13 ++++++++++++- .../reference/arrayIndexWithArrayFails.errors.txt | 9 +++++++++ .../reference/arrayIndexWithArrayFails.js | 7 +++++++ .../reference/arrayIndexWithArrayFails.symbols | 12 ++++++++++++ .../reference/arrayIndexWithArrayFails.types | 15 +++++++++++++++ .../keyofAndIndexedAccessErrors.errors.txt | 11 ++++++++++- tests/cases/compiler/arrayIndexWithArrayFails.ts | 3 +++ 7 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/arrayIndexWithArrayFails.errors.txt create mode 100644 tests/baselines/reference/arrayIndexWithArrayFails.js create mode 100644 tests/baselines/reference/arrayIndexWithArrayFails.symbols create mode 100644 tests/baselines/reference/arrayIndexWithArrayFails.types create mode 100644 tests/cases/compiler/arrayIndexWithArrayFails.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 394a5a581cbb7..9b7ceb5c02c93 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9361,13 +9361,24 @@ namespace ts { const apparentObjectType = getApparentType(objectType); if (indexType.flags & TypeFlags.Union && !(indexType.flags & TypeFlags.Boolean)) { const propTypes: Type[] = []; + let wasMissingProp: boolean | undefined; for (const t of (indexType).types) { const propType = getPropertyTypeForIndexType(apparentObjectType, t, accessNode, /*cacheSymbol*/ false, missingType); if (propType === missingType) { - return missingType; + if (!accessNode) { + // If there's no error node, we can immeditely stop, since error reporting is off + return missingType; + } + else { + // Otherwise we set a flag and return at the end of the loop so we still mark all errors + wasMissingProp = true; + } } propTypes.push(propType); } + if (wasMissingProp) { + return missingType; + } return getUnionType(propTypes); } return getPropertyTypeForIndexType(apparentObjectType, indexType, accessNode, /*cacheSymbol*/ true, missingType); diff --git a/tests/baselines/reference/arrayIndexWithArrayFails.errors.txt b/tests/baselines/reference/arrayIndexWithArrayFails.errors.txt new file mode 100644 index 0000000000000..bfe75e6d79c8c --- /dev/null +++ b/tests/baselines/reference/arrayIndexWithArrayFails.errors.txt @@ -0,0 +1,9 @@ +tests/cases/compiler/arrayIndexWithArrayFails.ts(3,16): error TS2538: Type 'string[]' cannot be used as an index type. + + +==== tests/cases/compiler/arrayIndexWithArrayFails.ts (1 errors) ==== + declare const arr1: (string | string[])[]; + declare const arr2: number[]; + const j = arr2[arr1[0]]; // should error + ~~~~~~~ +!!! error TS2538: Type 'string[]' cannot be used as an index type. \ No newline at end of file diff --git a/tests/baselines/reference/arrayIndexWithArrayFails.js b/tests/baselines/reference/arrayIndexWithArrayFails.js new file mode 100644 index 0000000000000..e5541a50704ea --- /dev/null +++ b/tests/baselines/reference/arrayIndexWithArrayFails.js @@ -0,0 +1,7 @@ +//// [arrayIndexWithArrayFails.ts] +declare const arr1: (string | string[])[]; +declare const arr2: number[]; +const j = arr2[arr1[0]]; // should error + +//// [arrayIndexWithArrayFails.js] +var j = arr2[arr1[0]]; // should error diff --git a/tests/baselines/reference/arrayIndexWithArrayFails.symbols b/tests/baselines/reference/arrayIndexWithArrayFails.symbols new file mode 100644 index 0000000000000..e389f29fbef6f --- /dev/null +++ b/tests/baselines/reference/arrayIndexWithArrayFails.symbols @@ -0,0 +1,12 @@ +=== tests/cases/compiler/arrayIndexWithArrayFails.ts === +declare const arr1: (string | string[])[]; +>arr1 : Symbol(arr1, Decl(arrayIndexWithArrayFails.ts, 0, 13)) + +declare const arr2: number[]; +>arr2 : Symbol(arr2, Decl(arrayIndexWithArrayFails.ts, 1, 13)) + +const j = arr2[arr1[0]]; // should error +>j : Symbol(j, Decl(arrayIndexWithArrayFails.ts, 2, 5)) +>arr2 : Symbol(arr2, Decl(arrayIndexWithArrayFails.ts, 1, 13)) +>arr1 : Symbol(arr1, Decl(arrayIndexWithArrayFails.ts, 0, 13)) + diff --git a/tests/baselines/reference/arrayIndexWithArrayFails.types b/tests/baselines/reference/arrayIndexWithArrayFails.types new file mode 100644 index 0000000000000..7e9b28f733c6e --- /dev/null +++ b/tests/baselines/reference/arrayIndexWithArrayFails.types @@ -0,0 +1,15 @@ +=== tests/cases/compiler/arrayIndexWithArrayFails.ts === +declare const arr1: (string | string[])[]; +>arr1 : (string | string[])[] + +declare const arr2: number[]; +>arr2 : number[] + +const j = arr2[arr1[0]]; // should error +>j : any +>arr2[arr1[0]] : any +>arr2 : number[] +>arr1[0] : string | string[] +>arr1 : (string | string[])[] +>0 : 0 + diff --git a/tests/baselines/reference/keyofAndIndexedAccessErrors.errors.txt b/tests/baselines/reference/keyofAndIndexedAccessErrors.errors.txt index 14cfbd1ceab29..dd5cbe050a902 100644 --- a/tests/baselines/reference/keyofAndIndexedAccessErrors.errors.txt +++ b/tests/baselines/reference/keyofAndIndexedAccessErrors.errors.txt @@ -8,9 +8,12 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(25,18): error tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(26,18): error TS2538: Type 'void' cannot be used as an index type. tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(27,18): error TS2538: Type 'undefined' cannot be used as an index type. tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(28,18): error TS2538: Type '{ x: string; }' cannot be used as an index type. +tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(29,18): error TS2537: Type 'Shape' has no matching index signature for type 'number'. tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(29,18): error TS2537: Type 'Shape' has no matching index signature for type 'string'. tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(30,18): error TS2538: Type 'string & number' cannot be used as an index type. tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(31,18): error TS2537: Type 'Shape' has no matching index signature for type 'string'. +tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(31,18): error TS2538: Type 'false' cannot be used as an index type. +tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(31,18): error TS2538: Type 'true' cannot be used as an index type. tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(35,21): error TS2537: Type 'string[]' has no matching index signature for type 'string'. tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(36,21): error TS2538: Type 'boolean' cannot be used as an index type. tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(41,31): error TS2538: Type 'boolean' cannot be used as an index type. @@ -60,7 +63,7 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(117,5): error Type 'T' is not assignable to type 'U'. -==== tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts (33 errors) ==== +==== tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts (36 errors) ==== class Shape { name: string; width: number; @@ -111,6 +114,8 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(117,5): error !!! error TS2538: Type '{ x: string; }' cannot be used as an index type. type T20 = Shape[string | number]; // Error ~~~~~~~~~~~~~~~ +!!! error TS2537: Type 'Shape' has no matching index signature for type 'number'. + ~~~~~~~~~~~~~~~ !!! error TS2537: Type 'Shape' has no matching index signature for type 'string'. type T21 = Shape[string & number]; // Error ~~~~~~~~~~~~~~~ @@ -118,6 +123,10 @@ tests/cases/conformance/types/keyof/keyofAndIndexedAccessErrors.ts(117,5): error type T22 = Shape[string | boolean]; // Error ~~~~~~~~~~~~~~~~ !!! error TS2537: Type 'Shape' has no matching index signature for type 'string'. + ~~~~~~~~~~~~~~~~ +!!! error TS2538: Type 'false' cannot be used as an index type. + ~~~~~~~~~~~~~~~~ +!!! error TS2538: Type 'true' cannot be used as an index type. type T30 = string[]["length"]; type T31 = string[][number]; diff --git a/tests/cases/compiler/arrayIndexWithArrayFails.ts b/tests/cases/compiler/arrayIndexWithArrayFails.ts new file mode 100644 index 0000000000000..242e1ff333443 --- /dev/null +++ b/tests/cases/compiler/arrayIndexWithArrayFails.ts @@ -0,0 +1,3 @@ +declare const arr1: (string | string[])[]; +declare const arr2: number[]; +const j = arr2[arr1[0]]; // should error \ No newline at end of file From cc68964e837e73de2aad66fb74ab30d78ba29253 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 4 Sep 2018 14:01:40 -0700 Subject: [PATCH 2/2] Change type a bit --- src/compiler/checker.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index 9b7ceb5c02c93..021864ec0bd37 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -9361,7 +9361,7 @@ namespace ts { const apparentObjectType = getApparentType(objectType); if (indexType.flags & TypeFlags.Union && !(indexType.flags & TypeFlags.Boolean)) { const propTypes: Type[] = []; - let wasMissingProp: boolean | undefined; + let wasMissingProp = false; for (const t of (indexType).types) { const propType = getPropertyTypeForIndexType(apparentObjectType, t, accessNode, /*cacheSymbol*/ false, missingType); if (propType === missingType) {