From 0a86b23a339552fc60c309898e09298ab4b7d17e Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 17 Apr 2018 14:45:51 -0700 Subject: [PATCH 1/4] Add implicit any errors for destructuring computed names which arent late bound and have no corresponding index --- src/compiler/checker.ts | 18 ++++- ...ndDestructuringImplicitAnyError.errors.txt | 30 ++++++++ .../lateBoundDestructuringImplicitAnyError.js | 35 ++++++++++ ...BoundDestructuringImplicitAnyError.symbols | 55 +++++++++++++++ ...teBoundDestructuringImplicitAnyError.types | 68 +++++++++++++++++++ .../lateBoundDestructuringImplicitAnyError.ts | 18 +++++ 6 files changed, 223 insertions(+), 1 deletion(-) create mode 100644 tests/baselines/reference/lateBoundDestructuringImplicitAnyError.errors.txt create mode 100644 tests/baselines/reference/lateBoundDestructuringImplicitAnyError.js create mode 100644 tests/baselines/reference/lateBoundDestructuringImplicitAnyError.symbols create mode 100644 tests/baselines/reference/lateBoundDestructuringImplicitAnyError.types create mode 100644 tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index d009a956c43ee..b9936919a052b 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4173,7 +4173,23 @@ namespace ts { const isLate = isLateBindableName(name); const isWellKnown = isComputedPropertyName(name) && isWellKnownSymbolSyntactically(name.expression); if (!isLate && !isWellKnown && isComputedNonLiteralName(name)) { - return anyType; + const exprType = checkExpression((name as ComputedPropertyName).expression); + let indexerType: Type; + if (isTypeAssignableToKind(exprType, TypeFlags.NumberLike)) { + indexerType = getIndexTypeOfType(parentType, IndexKind.Number); + } + else if (isTypeAssignableToKind(exprType, TypeFlags.StringLike)) { + indexerType = getIndexTypeOfType(parentType, IndexKind.String); + } + if (!indexerType && noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors) { + if (getIndexTypeOfType(parentType, IndexKind.Number)) { + error(declaration, Diagnostics.Element_implicitly_has_an_any_type_because_index_expression_is_not_of_type_number); + } + else { + error(declaration, Diagnostics.Element_implicitly_has_an_any_type_because_type_0_has_no_index_signature, typeToString(parentType)); + } + } + return indexerType || anyType; } // Use type of the specified property, or otherwise, for a numeric name, the type of the numeric index signature, diff --git a/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.errors.txt b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.errors.txt new file mode 100644 index 0000000000000..c22ec15a8be7d --- /dev/null +++ b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.errors.txt @@ -0,0 +1,30 @@ +tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts(2,15): error TS7017: Element implicitly has an 'any' type because type '{ prop: string; }' has no index signature. +tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts(10,15): error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'. +tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts(16,15): error TS7017: Element implicitly has an 'any' type because type '{ [idx: string]: string; }' has no index signature. + + +==== tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts (3 errors) ==== + let named = "foo"; + let {[named]: prop} = {prop: "foo"}; + ~~~~ +!!! error TS7017: Element implicitly has an 'any' type because type '{ prop: string; }' has no index signature. + void prop; + + const numIndexed: {[idx: number]: string} = null as any; + const strIndexed: {[idx: string]: string} = null as any; + + let numed = 6; + + let {[named]: prop2} = numIndexed; + ~~~~~ +!!! error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'. + void prop2; + let {[numed]: prop3} = numIndexed; + void prop3; + let {[named]: prop4} = strIndexed; + void prop4; + let {[numed]: prop5} = strIndexed; + ~~~~~ +!!! error TS7017: Element implicitly has an 'any' type because type '{ [idx: string]: string; }' has no index signature. + void prop5; + \ No newline at end of file diff --git a/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.js b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.js new file mode 100644 index 0000000000000..8e90ecd21debf --- /dev/null +++ b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.js @@ -0,0 +1,35 @@ +//// [lateBoundDestructuringImplicitAnyError.ts] +let named = "foo"; +let {[named]: prop} = {prop: "foo"}; +void prop; + +const numIndexed: {[idx: number]: string} = null as any; +const strIndexed: {[idx: string]: string} = null as any; + +let numed = 6; + +let {[named]: prop2} = numIndexed; +void prop2; +let {[numed]: prop3} = numIndexed; +void prop3; +let {[named]: prop4} = strIndexed; +void prop4; +let {[numed]: prop5} = strIndexed; +void prop5; + + +//// [lateBoundDestructuringImplicitAnyError.js] +var named = "foo"; +var _a = named, prop = { prop: "foo" }[_a]; +void prop; +var numIndexed = null; +var strIndexed = null; +var numed = 6; +var _b = named, prop2 = numIndexed[_b]; +void prop2; +var _c = numed, prop3 = numIndexed[_c]; +void prop3; +var _d = named, prop4 = strIndexed[_d]; +void prop4; +var _e = numed, prop5 = strIndexed[_e]; +void prop5; diff --git a/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.symbols b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.symbols new file mode 100644 index 0000000000000..0de90156feca7 --- /dev/null +++ b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.symbols @@ -0,0 +1,55 @@ +=== tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts === +let named = "foo"; +>named : Symbol(named, Decl(lateBoundDestructuringImplicitAnyError.ts, 0, 3)) + +let {[named]: prop} = {prop: "foo"}; +>named : Symbol(named, Decl(lateBoundDestructuringImplicitAnyError.ts, 0, 3)) +>prop : Symbol(prop, Decl(lateBoundDestructuringImplicitAnyError.ts, 1, 5)) +>prop : Symbol(prop, Decl(lateBoundDestructuringImplicitAnyError.ts, 1, 23)) + +void prop; +>prop : Symbol(prop, Decl(lateBoundDestructuringImplicitAnyError.ts, 1, 5)) + +const numIndexed: {[idx: number]: string} = null as any; +>numIndexed : Symbol(numIndexed, Decl(lateBoundDestructuringImplicitAnyError.ts, 4, 5)) +>idx : Symbol(idx, Decl(lateBoundDestructuringImplicitAnyError.ts, 4, 20)) + +const strIndexed: {[idx: string]: string} = null as any; +>strIndexed : Symbol(strIndexed, Decl(lateBoundDestructuringImplicitAnyError.ts, 5, 5)) +>idx : Symbol(idx, Decl(lateBoundDestructuringImplicitAnyError.ts, 5, 20)) + +let numed = 6; +>numed : Symbol(numed, Decl(lateBoundDestructuringImplicitAnyError.ts, 7, 3)) + +let {[named]: prop2} = numIndexed; +>named : Symbol(named, Decl(lateBoundDestructuringImplicitAnyError.ts, 0, 3)) +>prop2 : Symbol(prop2, Decl(lateBoundDestructuringImplicitAnyError.ts, 9, 5)) +>numIndexed : Symbol(numIndexed, Decl(lateBoundDestructuringImplicitAnyError.ts, 4, 5)) + +void prop2; +>prop2 : Symbol(prop2, Decl(lateBoundDestructuringImplicitAnyError.ts, 9, 5)) + +let {[numed]: prop3} = numIndexed; +>numed : Symbol(numed, Decl(lateBoundDestructuringImplicitAnyError.ts, 7, 3)) +>prop3 : Symbol(prop3, Decl(lateBoundDestructuringImplicitAnyError.ts, 11, 5)) +>numIndexed : Symbol(numIndexed, Decl(lateBoundDestructuringImplicitAnyError.ts, 4, 5)) + +void prop3; +>prop3 : Symbol(prop3, Decl(lateBoundDestructuringImplicitAnyError.ts, 11, 5)) + +let {[named]: prop4} = strIndexed; +>named : Symbol(named, Decl(lateBoundDestructuringImplicitAnyError.ts, 0, 3)) +>prop4 : Symbol(prop4, Decl(lateBoundDestructuringImplicitAnyError.ts, 13, 5)) +>strIndexed : Symbol(strIndexed, Decl(lateBoundDestructuringImplicitAnyError.ts, 5, 5)) + +void prop4; +>prop4 : Symbol(prop4, Decl(lateBoundDestructuringImplicitAnyError.ts, 13, 5)) + +let {[numed]: prop5} = strIndexed; +>numed : Symbol(numed, Decl(lateBoundDestructuringImplicitAnyError.ts, 7, 3)) +>prop5 : Symbol(prop5, Decl(lateBoundDestructuringImplicitAnyError.ts, 15, 5)) +>strIndexed : Symbol(strIndexed, Decl(lateBoundDestructuringImplicitAnyError.ts, 5, 5)) + +void prop5; +>prop5 : Symbol(prop5, Decl(lateBoundDestructuringImplicitAnyError.ts, 15, 5)) + diff --git a/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.types b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.types new file mode 100644 index 0000000000000..98d7152ef535e --- /dev/null +++ b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.types @@ -0,0 +1,68 @@ +=== tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts === +let named = "foo"; +>named : string +>"foo" : "foo" + +let {[named]: prop} = {prop: "foo"}; +>named : string +>prop : any +>{prop: "foo"} : { prop: string; } +>prop : string +>"foo" : "foo" + +void prop; +>void prop : undefined +>prop : any + +const numIndexed: {[idx: number]: string} = null as any; +>numIndexed : { [idx: number]: string; } +>idx : number +>null as any : any +>null : null + +const strIndexed: {[idx: string]: string} = null as any; +>strIndexed : { [idx: string]: string; } +>idx : string +>null as any : any +>null : null + +let numed = 6; +>numed : number +>6 : 6 + +let {[named]: prop2} = numIndexed; +>named : string +>prop2 : any +>numIndexed : { [idx: number]: string; } + +void prop2; +>void prop2 : undefined +>prop2 : any + +let {[numed]: prop3} = numIndexed; +>numed : number +>prop3 : string +>numIndexed : { [idx: number]: string; } + +void prop3; +>void prop3 : undefined +>prop3 : string + +let {[named]: prop4} = strIndexed; +>named : string +>prop4 : string +>strIndexed : { [idx: string]: string; } + +void prop4; +>void prop4 : undefined +>prop4 : string + +let {[numed]: prop5} = strIndexed; +>numed : number +>prop5 : any +>strIndexed : { [idx: string]: string; } + +void prop5; +>void prop5 : undefined +>prop5 : any + diff --git a/tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts b/tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts new file mode 100644 index 0000000000000..a06bfa290d9a6 --- /dev/null +++ b/tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts @@ -0,0 +1,18 @@ +// @noImplicitAny: true +let named = "foo"; +let {[named]: prop} = {prop: "foo"}; +void prop; + +const numIndexed: {[idx: number]: string} = null as any; +const strIndexed: {[idx: string]: string} = null as any; + +let numed = 6; + +let {[named]: prop2} = numIndexed; +void prop2; +let {[numed]: prop3} = numIndexed; +void prop3; +let {[named]: prop4} = strIndexed; +void prop4; +let {[numed]: prop5} = strIndexed; +void prop5; From d965c33c9a101c2a954df40652bdbab3698cf592 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Tue, 17 Apr 2018 15:51:15 -0700 Subject: [PATCH 2/4] Add string fallback for number --- src/compiler/checker.ts | 2 +- .../lateBoundDestructuringImplicitAnyError.errors.txt | 5 +---- .../reference/lateBoundDestructuringImplicitAnyError.types | 4 ++-- 3 files changed, 4 insertions(+), 7 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index b9936919a052b..f487815c63f37 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4176,7 +4176,7 @@ namespace ts { const exprType = checkExpression((name as ComputedPropertyName).expression); let indexerType: Type; if (isTypeAssignableToKind(exprType, TypeFlags.NumberLike)) { - indexerType = getIndexTypeOfType(parentType, IndexKind.Number); + indexerType = getIndexTypeOfType(parentType, IndexKind.Number) || getIndexTypeOfType(parentType, IndexKind.String); } else if (isTypeAssignableToKind(exprType, TypeFlags.StringLike)) { indexerType = getIndexTypeOfType(parentType, IndexKind.String); diff --git a/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.errors.txt b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.errors.txt index c22ec15a8be7d..862cf74be623e 100644 --- a/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.errors.txt +++ b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.errors.txt @@ -1,9 +1,8 @@ tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts(2,15): error TS7017: Element implicitly has an 'any' type because type '{ prop: string; }' has no index signature. tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts(10,15): error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'. -tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts(16,15): error TS7017: Element implicitly has an 'any' type because type '{ [idx: string]: string; }' has no index signature. -==== tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts (3 errors) ==== +==== tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts (2 errors) ==== let named = "foo"; let {[named]: prop} = {prop: "foo"}; ~~~~ @@ -24,7 +23,5 @@ tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts(16,15): error TS7 let {[named]: prop4} = strIndexed; void prop4; let {[numed]: prop5} = strIndexed; - ~~~~~ -!!! error TS7017: Element implicitly has an 'any' type because type '{ [idx: string]: string; }' has no index signature. void prop5; \ No newline at end of file diff --git a/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.types b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.types index 98d7152ef535e..7f8aa3fe0b49c 100644 --- a/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.types +++ b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.types @@ -59,10 +59,10 @@ void prop4; let {[numed]: prop5} = strIndexed; >numed : number ->prop5 : any +>prop5 : string >strIndexed : { [idx: string]: string; } void prop5; >void prop5 : undefined ->prop5 : any +>prop5 : string From 4fa8c07a8eb6cd9da703a571bdf76bb858cbb776 Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Wed, 18 Apr 2018 16:23:41 -0700 Subject: [PATCH 3/4] Expand test case, make functionality mimic other (buggy) areas --- src/compiler/checker.ts | 8 +---- ...ndDestructuringImplicitAnyError.errors.txt | 13 +++++-- .../lateBoundDestructuringImplicitAnyError.js | 11 ++++++ ...BoundDestructuringImplicitAnyError.symbols | 36 ++++++++++++++----- ...teBoundDestructuringImplicitAnyError.types | 23 ++++++++++++ .../lateBoundDestructuringImplicitAnyError.ts | 7 ++++ 6 files changed, 81 insertions(+), 17 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index f487815c63f37..9b4ee5f2987d4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4174,13 +4174,7 @@ namespace ts { const isWellKnown = isComputedPropertyName(name) && isWellKnownSymbolSyntactically(name.expression); if (!isLate && !isWellKnown && isComputedNonLiteralName(name)) { const exprType = checkExpression((name as ComputedPropertyName).expression); - let indexerType: Type; - if (isTypeAssignableToKind(exprType, TypeFlags.NumberLike)) { - indexerType = getIndexTypeOfType(parentType, IndexKind.Number) || getIndexTypeOfType(parentType, IndexKind.String); - } - else if (isTypeAssignableToKind(exprType, TypeFlags.StringLike)) { - indexerType = getIndexTypeOfType(parentType, IndexKind.String); - } + const indexerType = isTypeAssignableToKind(exprType, TypeFlags.NumberLike) && getIndexTypeOfType(parentType, IndexKind.Number) || getIndexTypeOfType(parentType, IndexKind.String); if (!indexerType && noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors) { if (getIndexTypeOfType(parentType, IndexKind.Number)) { error(declaration, Diagnostics.Element_implicitly_has_an_any_type_because_index_expression_is_not_of_type_number); diff --git a/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.errors.txt b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.errors.txt index 862cf74be623e..4233a67f7409b 100644 --- a/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.errors.txt +++ b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.errors.txt @@ -1,8 +1,9 @@ tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts(2,15): error TS7017: Element implicitly has an 'any' type because type '{ prop: string; }' has no index signature. -tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts(10,15): error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'. +tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts(12,15): error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'. +tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts(20,6): error TS2459: Type '{ [idx: number]: string; }' has no property '[symed]' and no string index signature. -==== tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts (2 errors) ==== +==== tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts (3 errors) ==== let named = "foo"; let {[named]: prop} = {prop: "foo"}; ~~~~ @@ -14,6 +15,8 @@ tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts(10,15): error TS7 let numed = 6; + const symed = Symbol() + let {[named]: prop2} = numIndexed; ~~~~~ !!! error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'. @@ -24,4 +27,10 @@ tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts(10,15): error TS7 void prop4; let {[numed]: prop5} = strIndexed; void prop5; + let {[symed]: prop6} = numIndexed; + ~~~~~~~ +!!! error TS2459: Type '{ [idx: number]: string; }' has no property '[symed]' and no string index signature. + void prop6; + let {[symed]: prop7} = strIndexed; + void prop7; \ No newline at end of file diff --git a/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.js b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.js index 8e90ecd21debf..842de290acea0 100644 --- a/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.js +++ b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.js @@ -8,6 +8,8 @@ const strIndexed: {[idx: string]: string} = null as any; let numed = 6; +const symed = Symbol() + let {[named]: prop2} = numIndexed; void prop2; let {[numed]: prop3} = numIndexed; @@ -16,6 +18,10 @@ let {[named]: prop4} = strIndexed; void prop4; let {[numed]: prop5} = strIndexed; void prop5; +let {[symed]: prop6} = numIndexed; +void prop6; +let {[symed]: prop7} = strIndexed; +void prop7; //// [lateBoundDestructuringImplicitAnyError.js] @@ -25,6 +31,7 @@ void prop; var numIndexed = null; var strIndexed = null; var numed = 6; +var symed = Symbol(); var _b = named, prop2 = numIndexed[_b]; void prop2; var _c = numed, prop3 = numIndexed[_c]; @@ -33,3 +40,7 @@ var _d = named, prop4 = strIndexed[_d]; void prop4; var _e = numed, prop5 = strIndexed[_e]; void prop5; +var _f = symed, prop6 = numIndexed[_f]; +void prop6; +var _g = symed, prop7 = strIndexed[_g]; +void prop7; diff --git a/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.symbols b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.symbols index 0de90156feca7..77f35cd728d80 100644 --- a/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.symbols +++ b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.symbols @@ -21,35 +21,55 @@ const strIndexed: {[idx: string]: string} = null as any; let numed = 6; >numed : Symbol(numed, Decl(lateBoundDestructuringImplicitAnyError.ts, 7, 3)) +const symed = Symbol() +>symed : Symbol(symed, Decl(lateBoundDestructuringImplicitAnyError.ts, 9, 5)) +>Symbol : Symbol(Symbol, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --)) + let {[named]: prop2} = numIndexed; >named : Symbol(named, Decl(lateBoundDestructuringImplicitAnyError.ts, 0, 3)) ->prop2 : Symbol(prop2, Decl(lateBoundDestructuringImplicitAnyError.ts, 9, 5)) +>prop2 : Symbol(prop2, Decl(lateBoundDestructuringImplicitAnyError.ts, 11, 5)) >numIndexed : Symbol(numIndexed, Decl(lateBoundDestructuringImplicitAnyError.ts, 4, 5)) void prop2; ->prop2 : Symbol(prop2, Decl(lateBoundDestructuringImplicitAnyError.ts, 9, 5)) +>prop2 : Symbol(prop2, Decl(lateBoundDestructuringImplicitAnyError.ts, 11, 5)) let {[numed]: prop3} = numIndexed; >numed : Symbol(numed, Decl(lateBoundDestructuringImplicitAnyError.ts, 7, 3)) ->prop3 : Symbol(prop3, Decl(lateBoundDestructuringImplicitAnyError.ts, 11, 5)) +>prop3 : Symbol(prop3, Decl(lateBoundDestructuringImplicitAnyError.ts, 13, 5)) >numIndexed : Symbol(numIndexed, Decl(lateBoundDestructuringImplicitAnyError.ts, 4, 5)) void prop3; ->prop3 : Symbol(prop3, Decl(lateBoundDestructuringImplicitAnyError.ts, 11, 5)) +>prop3 : Symbol(prop3, Decl(lateBoundDestructuringImplicitAnyError.ts, 13, 5)) let {[named]: prop4} = strIndexed; >named : Symbol(named, Decl(lateBoundDestructuringImplicitAnyError.ts, 0, 3)) ->prop4 : Symbol(prop4, Decl(lateBoundDestructuringImplicitAnyError.ts, 13, 5)) +>prop4 : Symbol(prop4, Decl(lateBoundDestructuringImplicitAnyError.ts, 15, 5)) >strIndexed : Symbol(strIndexed, Decl(lateBoundDestructuringImplicitAnyError.ts, 5, 5)) void prop4; ->prop4 : Symbol(prop4, Decl(lateBoundDestructuringImplicitAnyError.ts, 13, 5)) +>prop4 : Symbol(prop4, Decl(lateBoundDestructuringImplicitAnyError.ts, 15, 5)) let {[numed]: prop5} = strIndexed; >numed : Symbol(numed, Decl(lateBoundDestructuringImplicitAnyError.ts, 7, 3)) ->prop5 : Symbol(prop5, Decl(lateBoundDestructuringImplicitAnyError.ts, 15, 5)) +>prop5 : Symbol(prop5, Decl(lateBoundDestructuringImplicitAnyError.ts, 17, 5)) >strIndexed : Symbol(strIndexed, Decl(lateBoundDestructuringImplicitAnyError.ts, 5, 5)) void prop5; ->prop5 : Symbol(prop5, Decl(lateBoundDestructuringImplicitAnyError.ts, 15, 5)) +>prop5 : Symbol(prop5, Decl(lateBoundDestructuringImplicitAnyError.ts, 17, 5)) + +let {[symed]: prop6} = numIndexed; +>symed : Symbol(symed, Decl(lateBoundDestructuringImplicitAnyError.ts, 9, 5)) +>prop6 : Symbol(prop6, Decl(lateBoundDestructuringImplicitAnyError.ts, 19, 5)) +>numIndexed : Symbol(numIndexed, Decl(lateBoundDestructuringImplicitAnyError.ts, 4, 5)) + +void prop6; +>prop6 : Symbol(prop6, Decl(lateBoundDestructuringImplicitAnyError.ts, 19, 5)) + +let {[symed]: prop7} = strIndexed; +>symed : Symbol(symed, Decl(lateBoundDestructuringImplicitAnyError.ts, 9, 5)) +>prop7 : Symbol(prop7, Decl(lateBoundDestructuringImplicitAnyError.ts, 21, 5)) +>strIndexed : Symbol(strIndexed, Decl(lateBoundDestructuringImplicitAnyError.ts, 5, 5)) + +void prop7; +>prop7 : Symbol(prop7, Decl(lateBoundDestructuringImplicitAnyError.ts, 21, 5)) diff --git a/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.types b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.types index 7f8aa3fe0b49c..cf1b3ef6fe6bb 100644 --- a/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.types +++ b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.types @@ -30,6 +30,11 @@ let numed = 6; >numed : number >6 : 6 +const symed = Symbol() +>symed : unique symbol +>Symbol() : unique symbol +>Symbol : SymbolConstructor + let {[named]: prop2} = numIndexed; >named : string >prop2 : any @@ -66,3 +71,21 @@ void prop5; >void prop5 : undefined >prop5 : string +let {[symed]: prop6} = numIndexed; +>symed : unique symbol +>prop6 : any +>numIndexed : { [idx: number]: string; } + +void prop6; +>void prop6 : undefined +>prop6 : any + +let {[symed]: prop7} = strIndexed; +>symed : unique symbol +>prop7 : string +>strIndexed : { [idx: string]: string; } + +void prop7; +>void prop7 : undefined +>prop7 : string + diff --git a/tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts b/tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts index a06bfa290d9a6..6c9f4898fef99 100644 --- a/tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts +++ b/tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts @@ -1,3 +1,4 @@ +// @lib: es6 // @noImplicitAny: true let named = "foo"; let {[named]: prop} = {prop: "foo"}; @@ -8,6 +9,8 @@ const strIndexed: {[idx: string]: string} = null as any; let numed = 6; +const symed = Symbol() + let {[named]: prop2} = numIndexed; void prop2; let {[numed]: prop3} = numIndexed; @@ -16,3 +19,7 @@ let {[named]: prop4} = strIndexed; void prop4; let {[numed]: prop5} = strIndexed; void prop5; +let {[symed]: prop6} = numIndexed; +void prop6; +let {[symed]: prop7} = strIndexed; +void prop7; From 40ab991e40575824aba005a2afc899727c2e044f Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Fri, 27 Apr 2018 13:50:14 -0700 Subject: [PATCH 4/4] Add symbol name errors to bring in line with new indexing rules --- src/compiler/checker.ts | 15 +++++- ...ndDestructuringImplicitAnyError.errors.txt | 27 ++++++++--- .../lateBoundDestructuringImplicitAnyError.js | 13 +++++- ...BoundDestructuringImplicitAnyError.symbols | 46 +++++++++++++------ ...teBoundDestructuringImplicitAnyError.types | 29 ++++++++++-- .../lateBoundDestructuringImplicitAnyError.ts | 7 ++- 6 files changed, 110 insertions(+), 27 deletions(-) diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts index a7f71004e00a6..0458cc6c0fcd4 100644 --- a/src/compiler/checker.ts +++ b/src/compiler/checker.ts @@ -4228,6 +4228,12 @@ namespace ts { const isWellKnown = isComputedPropertyName(name) && isWellKnownSymbolSyntactically(name.expression); if (!isLate && !isWellKnown && isComputedNonLiteralName(name)) { const exprType = checkExpression((name as ComputedPropertyName).expression); + if (isTypeAssignableToKind(exprType, TypeFlags.ESSymbolLike)) { + if (noImplicitAny) { + error(declaration, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(exprType), typeToString(parentType)); + } + return anyType; + } const indexerType = isTypeAssignableToKind(exprType, TypeFlags.NumberLike) && getIndexTypeOfType(parentType, IndexKind.Number) || getIndexTypeOfType(parentType, IndexKind.String); if (!indexerType && noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors) { if (getIndexTypeOfType(parentType, IndexKind.Number)) { @@ -4242,7 +4248,8 @@ namespace ts { // Use type of the specified property, or otherwise, for a numeric name, the type of the numeric index signature, // or otherwise the type of the string index signature. - const text = isLate ? getLateBoundNameFromType(checkComputedPropertyName(name as ComputedPropertyName) as LiteralType | UniqueESSymbolType) : + const nameType = isLate && checkComputedPropertyName(name as ComputedPropertyName) as LiteralType | UniqueESSymbolType; + const text = isLate ? getLateBoundNameFromType(nameType) : isWellKnown ? getPropertyNameForKnownSymbolName(idText(((name as ComputedPropertyName).expression as PropertyAccessExpression).name)) : getTextOfPropertyName(name); @@ -4250,6 +4257,12 @@ namespace ts { if (strictNullChecks && declaration.flags & NodeFlags.Ambient && isParameterDeclaration(declaration)) { parentType = getNonNullableType(parentType); } + if (isLate && nameType && !getPropertyOfType(parentType, text) && isTypeAssignableToKind(nameType, TypeFlags.ESSymbolLike)) { + if (noImplicitAny) { + error(declaration, Diagnostics.Type_0_cannot_be_used_to_index_type_1, typeToString(nameType), typeToString(parentType)); + } + return anyType; + } const declaredType = getConstraintForLocation(getTypeOfPropertyOfType(parentType, text), declaration.name); type = declaredType && getFlowTypeOfReference(declaration, declaredType) || isNumericLiteralName(text) && getIndexTypeOfType(parentType, IndexKind.Number) || diff --git a/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.errors.txt b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.errors.txt index 4233a67f7409b..2e926ac1b83d3 100644 --- a/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.errors.txt +++ b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.errors.txt @@ -1,9 +1,12 @@ tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts(2,15): error TS7017: Element implicitly has an 'any' type because type '{ prop: string; }' has no index signature. -tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts(12,15): error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'. -tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts(20,6): error TS2459: Type '{ [idx: number]: string; }' has no property '[symed]' and no string index signature. +tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts(13,15): error TS7015: Element implicitly has an 'any' type because index expression is not of type 'number'. +tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts(21,15): error TS2536: Type 'unique symbol' cannot be used to index type '{ [idx: number]: string; }'. +tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts(23,15): error TS2536: Type 'unique symbol' cannot be used to index type '{ [idx: string]: string; }'. +tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts(25,16): error TS2536: Type 'symbol' cannot be used to index type '{ [idx: number]: string; }'. +tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts(27,16): error TS2536: Type 'symbol' cannot be used to index type '{ [idx: string]: string; }'. -==== tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts (3 errors) ==== +==== tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts (6 errors) ==== let named = "foo"; let {[named]: prop} = {prop: "foo"}; ~~~~ @@ -15,7 +18,8 @@ tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts(20,6): error TS24 let numed = 6; - const symed = Symbol() + const symed = Symbol(); + let symed2 = Symbol(); let {[named]: prop2} = numIndexed; ~~~~~ @@ -28,9 +32,18 @@ tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts(20,6): error TS24 let {[numed]: prop5} = strIndexed; void prop5; let {[symed]: prop6} = numIndexed; - ~~~~~~~ -!!! error TS2459: Type '{ [idx: number]: string; }' has no property '[symed]' and no string index signature. + ~~~~~ +!!! error TS2536: Type 'unique symbol' cannot be used to index type '{ [idx: number]: string; }'. void prop6; let {[symed]: prop7} = strIndexed; + ~~~~~ +!!! error TS2536: Type 'unique symbol' cannot be used to index type '{ [idx: string]: string; }'. void prop7; - \ No newline at end of file + let {[symed2]: prop8} = numIndexed; + ~~~~~ +!!! error TS2536: Type 'symbol' cannot be used to index type '{ [idx: number]: string; }'. + void prop8; + let {[symed2]: prop9} = strIndexed; + ~~~~~ +!!! error TS2536: Type 'symbol' cannot be used to index type '{ [idx: string]: string; }'. + void prop9; \ No newline at end of file diff --git a/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.js b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.js index 842de290acea0..61331a135649f 100644 --- a/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.js +++ b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.js @@ -8,7 +8,8 @@ const strIndexed: {[idx: string]: string} = null as any; let numed = 6; -const symed = Symbol() +const symed = Symbol(); +let symed2 = Symbol(); let {[named]: prop2} = numIndexed; void prop2; @@ -22,7 +23,10 @@ let {[symed]: prop6} = numIndexed; void prop6; let {[symed]: prop7} = strIndexed; void prop7; - +let {[symed2]: prop8} = numIndexed; +void prop8; +let {[symed2]: prop9} = strIndexed; +void prop9; //// [lateBoundDestructuringImplicitAnyError.js] var named = "foo"; @@ -32,6 +36,7 @@ var numIndexed = null; var strIndexed = null; var numed = 6; var symed = Symbol(); +var symed2 = Symbol(); var _b = named, prop2 = numIndexed[_b]; void prop2; var _c = numed, prop3 = numIndexed[_c]; @@ -44,3 +49,7 @@ var _f = symed, prop6 = numIndexed[_f]; void prop6; var _g = symed, prop7 = strIndexed[_g]; void prop7; +var _h = symed2, prop8 = numIndexed[_h]; +void prop8; +var _j = symed2, prop9 = strIndexed[_j]; +void prop9; diff --git a/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.symbols b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.symbols index 77f35cd728d80..28bdf34a2abee 100644 --- a/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.symbols +++ b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.symbols @@ -21,55 +21,75 @@ const strIndexed: {[idx: string]: string} = null as any; let numed = 6; >numed : Symbol(numed, Decl(lateBoundDestructuringImplicitAnyError.ts, 7, 3)) -const symed = Symbol() +const symed = Symbol(); >symed : Symbol(symed, Decl(lateBoundDestructuringImplicitAnyError.ts, 9, 5)) >Symbol : Symbol(Symbol, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --)) +let symed2 = Symbol(); +>symed2 : Symbol(symed2, Decl(lateBoundDestructuringImplicitAnyError.ts, 10, 3)) +>Symbol : Symbol(Symbol, Decl(lib.es2015.symbol.wellknown.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --), Decl(lib.es2015.symbol.d.ts, --, --)) + let {[named]: prop2} = numIndexed; >named : Symbol(named, Decl(lateBoundDestructuringImplicitAnyError.ts, 0, 3)) ->prop2 : Symbol(prop2, Decl(lateBoundDestructuringImplicitAnyError.ts, 11, 5)) +>prop2 : Symbol(prop2, Decl(lateBoundDestructuringImplicitAnyError.ts, 12, 5)) >numIndexed : Symbol(numIndexed, Decl(lateBoundDestructuringImplicitAnyError.ts, 4, 5)) void prop2; ->prop2 : Symbol(prop2, Decl(lateBoundDestructuringImplicitAnyError.ts, 11, 5)) +>prop2 : Symbol(prop2, Decl(lateBoundDestructuringImplicitAnyError.ts, 12, 5)) let {[numed]: prop3} = numIndexed; >numed : Symbol(numed, Decl(lateBoundDestructuringImplicitAnyError.ts, 7, 3)) ->prop3 : Symbol(prop3, Decl(lateBoundDestructuringImplicitAnyError.ts, 13, 5)) +>prop3 : Symbol(prop3, Decl(lateBoundDestructuringImplicitAnyError.ts, 14, 5)) >numIndexed : Symbol(numIndexed, Decl(lateBoundDestructuringImplicitAnyError.ts, 4, 5)) void prop3; ->prop3 : Symbol(prop3, Decl(lateBoundDestructuringImplicitAnyError.ts, 13, 5)) +>prop3 : Symbol(prop3, Decl(lateBoundDestructuringImplicitAnyError.ts, 14, 5)) let {[named]: prop4} = strIndexed; >named : Symbol(named, Decl(lateBoundDestructuringImplicitAnyError.ts, 0, 3)) ->prop4 : Symbol(prop4, Decl(lateBoundDestructuringImplicitAnyError.ts, 15, 5)) +>prop4 : Symbol(prop4, Decl(lateBoundDestructuringImplicitAnyError.ts, 16, 5)) >strIndexed : Symbol(strIndexed, Decl(lateBoundDestructuringImplicitAnyError.ts, 5, 5)) void prop4; ->prop4 : Symbol(prop4, Decl(lateBoundDestructuringImplicitAnyError.ts, 15, 5)) +>prop4 : Symbol(prop4, Decl(lateBoundDestructuringImplicitAnyError.ts, 16, 5)) let {[numed]: prop5} = strIndexed; >numed : Symbol(numed, Decl(lateBoundDestructuringImplicitAnyError.ts, 7, 3)) ->prop5 : Symbol(prop5, Decl(lateBoundDestructuringImplicitAnyError.ts, 17, 5)) +>prop5 : Symbol(prop5, Decl(lateBoundDestructuringImplicitAnyError.ts, 18, 5)) >strIndexed : Symbol(strIndexed, Decl(lateBoundDestructuringImplicitAnyError.ts, 5, 5)) void prop5; ->prop5 : Symbol(prop5, Decl(lateBoundDestructuringImplicitAnyError.ts, 17, 5)) +>prop5 : Symbol(prop5, Decl(lateBoundDestructuringImplicitAnyError.ts, 18, 5)) let {[symed]: prop6} = numIndexed; >symed : Symbol(symed, Decl(lateBoundDestructuringImplicitAnyError.ts, 9, 5)) ->prop6 : Symbol(prop6, Decl(lateBoundDestructuringImplicitAnyError.ts, 19, 5)) +>prop6 : Symbol(prop6, Decl(lateBoundDestructuringImplicitAnyError.ts, 20, 5)) >numIndexed : Symbol(numIndexed, Decl(lateBoundDestructuringImplicitAnyError.ts, 4, 5)) void prop6; ->prop6 : Symbol(prop6, Decl(lateBoundDestructuringImplicitAnyError.ts, 19, 5)) +>prop6 : Symbol(prop6, Decl(lateBoundDestructuringImplicitAnyError.ts, 20, 5)) let {[symed]: prop7} = strIndexed; >symed : Symbol(symed, Decl(lateBoundDestructuringImplicitAnyError.ts, 9, 5)) ->prop7 : Symbol(prop7, Decl(lateBoundDestructuringImplicitAnyError.ts, 21, 5)) +>prop7 : Symbol(prop7, Decl(lateBoundDestructuringImplicitAnyError.ts, 22, 5)) >strIndexed : Symbol(strIndexed, Decl(lateBoundDestructuringImplicitAnyError.ts, 5, 5)) void prop7; ->prop7 : Symbol(prop7, Decl(lateBoundDestructuringImplicitAnyError.ts, 21, 5)) +>prop7 : Symbol(prop7, Decl(lateBoundDestructuringImplicitAnyError.ts, 22, 5)) + +let {[symed2]: prop8} = numIndexed; +>symed2 : Symbol(symed2, Decl(lateBoundDestructuringImplicitAnyError.ts, 10, 3)) +>prop8 : Symbol(prop8, Decl(lateBoundDestructuringImplicitAnyError.ts, 24, 5)) +>numIndexed : Symbol(numIndexed, Decl(lateBoundDestructuringImplicitAnyError.ts, 4, 5)) + +void prop8; +>prop8 : Symbol(prop8, Decl(lateBoundDestructuringImplicitAnyError.ts, 24, 5)) + +let {[symed2]: prop9} = strIndexed; +>symed2 : Symbol(symed2, Decl(lateBoundDestructuringImplicitAnyError.ts, 10, 3)) +>prop9 : Symbol(prop9, Decl(lateBoundDestructuringImplicitAnyError.ts, 26, 5)) +>strIndexed : Symbol(strIndexed, Decl(lateBoundDestructuringImplicitAnyError.ts, 5, 5)) + +void prop9; +>prop9 : Symbol(prop9, Decl(lateBoundDestructuringImplicitAnyError.ts, 26, 5)) diff --git a/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.types b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.types index cf1b3ef6fe6bb..92d2c4c662c4b 100644 --- a/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.types +++ b/tests/baselines/reference/lateBoundDestructuringImplicitAnyError.types @@ -30,11 +30,16 @@ let numed = 6; >numed : number >6 : 6 -const symed = Symbol() +const symed = Symbol(); >symed : unique symbol >Symbol() : unique symbol >Symbol : SymbolConstructor +let symed2 = Symbol(); +>symed2 : symbol +>Symbol() : symbol +>Symbol : SymbolConstructor + let {[named]: prop2} = numIndexed; >named : string >prop2 : any @@ -82,10 +87,28 @@ void prop6; let {[symed]: prop7} = strIndexed; >symed : unique symbol ->prop7 : string +>prop7 : any >strIndexed : { [idx: string]: string; } void prop7; >void prop7 : undefined ->prop7 : string +>prop7 : any + +let {[symed2]: prop8} = numIndexed; +>symed2 : symbol +>prop8 : any +>numIndexed : { [idx: number]: string; } + +void prop8; +>void prop8 : undefined +>prop8 : any + +let {[symed2]: prop9} = strIndexed; +>symed2 : symbol +>prop9 : any +>strIndexed : { [idx: string]: string; } + +void prop9; +>void prop9 : undefined +>prop9 : any diff --git a/tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts b/tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts index 6c9f4898fef99..800675c7823f7 100644 --- a/tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts +++ b/tests/cases/compiler/lateBoundDestructuringImplicitAnyError.ts @@ -9,7 +9,8 @@ const strIndexed: {[idx: string]: string} = null as any; let numed = 6; -const symed = Symbol() +const symed = Symbol(); +let symed2 = Symbol(); let {[named]: prop2} = numIndexed; void prop2; @@ -23,3 +24,7 @@ let {[symed]: prop6} = numIndexed; void prop6; let {[symed]: prop7} = strIndexed; void prop7; +let {[symed2]: prop8} = numIndexed; +void prop8; +let {[symed2]: prop9} = strIndexed; +void prop9; \ No newline at end of file