Add implicit any errors for destructuring computed names which aren't late bound and have no corresponding index (#23489)

* Add implicit any errors for destructuring computed names which arent late bound and have no corresponding index

* Add string fallback for number

* Expand test case, make functionality mimic other (buggy) areas

* Add symbol name errors to bring in line with new indexing rules
This commit is contained in:
Wesley Wigham 2018-04-27 15:55:32 -07:00 committed by GitHub
parent 6c28da328e
commit 6d3b6e21da
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 368 additions and 2 deletions

View file

@ -4227,12 +4227,29 @@ 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);
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)) {
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,
// 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);
@ -4240,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) ||

View file

@ -0,0 +1,49 @@
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(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 (6 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;
const symed = Symbol();
let symed2 = Symbol();
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;
void prop5;
let {[symed]: prop6} = numIndexed;
~~~~~
!!! 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;
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;

View file

@ -0,0 +1,55 @@
//// [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;
const symed = Symbol();
let symed2 = Symbol();
let {[named]: prop2} = numIndexed;
void prop2;
let {[numed]: prop3} = numIndexed;
void prop3;
let {[named]: prop4} = strIndexed;
void prop4;
let {[numed]: prop5} = strIndexed;
void prop5;
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";
var _a = named, prop = { prop: "foo" }[_a];
void prop;
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];
void prop3;
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;
var _h = symed2, prop8 = numIndexed[_h];
void prop8;
var _j = symed2, prop9 = strIndexed[_j];
void prop9;

View file

@ -0,0 +1,95 @@
=== 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))
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, 12, 5))
>numIndexed : Symbol(numIndexed, Decl(lateBoundDestructuringImplicitAnyError.ts, 4, 5))
void prop2;
>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, 14, 5))
>numIndexed : Symbol(numIndexed, Decl(lateBoundDestructuringImplicitAnyError.ts, 4, 5))
void prop3;
>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, 16, 5))
>strIndexed : Symbol(strIndexed, Decl(lateBoundDestructuringImplicitAnyError.ts, 5, 5))
void prop4;
>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, 18, 5))
>strIndexed : Symbol(strIndexed, Decl(lateBoundDestructuringImplicitAnyError.ts, 5, 5))
void prop5;
>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, 20, 5))
>numIndexed : Symbol(numIndexed, Decl(lateBoundDestructuringImplicitAnyError.ts, 4, 5))
void prop6;
>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, 22, 5))
>strIndexed : Symbol(strIndexed, Decl(lateBoundDestructuringImplicitAnyError.ts, 5, 5))
void prop7;
>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))

View file

@ -0,0 +1,114 @@
=== 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
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
>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 : string
>strIndexed : { [idx: string]: string; }
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 : any
>strIndexed : { [idx: string]: string; }
void prop7;
>void prop7 : undefined
>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

View file

@ -0,0 +1,30 @@
// @lib: es6
// @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;
const symed = Symbol();
let symed2 = Symbol();
let {[named]: prop2} = numIndexed;
void prop2;
let {[numed]: prop3} = numIndexed;
void prop3;
let {[named]: prop4} = strIndexed;
void prop4;
let {[numed]: prop5} = strIndexed;
void prop5;
let {[symed]: prop6} = numIndexed;
void prop6;
let {[symed]: prop7} = strIndexed;
void prop7;
let {[symed2]: prop8} = numIndexed;
void prop8;
let {[symed2]: prop9} = strIndexed;
void prop9;