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:
parent
6c28da328e
commit
6d3b6e21da
6 changed files with 368 additions and 2 deletions
|
@ -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) ||
|
||||
|
|
|
@ -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;
|
|
@ -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;
|
|
@ -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))
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
Loading…
Reference in a new issue