Check for numeric index signature instead of array-like type

Better error message when object with numeric index signature is indexed with a string
This commit is contained in:
Anders Hejlsberg 2016-01-07 10:34:22 -08:00
parent 537fb4a7c5
commit 3344a42686
2 changed files with 19 additions and 6 deletions

View file

@ -8581,10 +8581,17 @@ namespace ts {
}
/**
* Return true if given node is an expression consisting of an identifier (possibly parenthesized)
* that references a variable declared in a containing for-in statement for an array-like object.
* Return true if the given type is considered to have numeric property names.
*/
function isForInVariableForArrayLikeObject(expr: Expression) {
function hasNumericPropertyNames(type: Type) {
return getIndexTypeOfType(type, IndexKind.Number) && !getIndexTypeOfType(type, IndexKind.String);
}
/**
* Return true if given node is an expression consisting of an identifier (possibly parenthesized)
* that references a for-in variable for an object with numeric property names.
*/
function isForInVariableForNumericPropertyNames(expr: Expression) {
const e = skipParenthesizedNodes(expr);
if (e.kind === SyntaxKind.Identifier) {
const symbol = getResolvedSymbol(<Identifier>e);
@ -8595,7 +8602,7 @@ namespace ts {
if (node.kind === SyntaxKind.ForInStatement &&
child === (<ForInStatement>node).statement &&
getForInVariableSymbol(<ForInStatement>node) === symbol &&
isArrayLikeType(checkExpression((<ForInStatement>node).expression))) {
hasNumericPropertyNames(checkExpression((<ForInStatement>node).expression))) {
return true;
}
child = node;
@ -8666,7 +8673,7 @@ namespace ts {
if (isTypeAnyOrAllConstituentTypesHaveKind(indexType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbol)) {
// Try to use a number indexer.
if (isTypeAnyOrAllConstituentTypesHaveKind(indexType, TypeFlags.NumberLike) || isForInVariableForArrayLikeObject(node.argumentExpression)) {
if (isTypeAnyOrAllConstituentTypesHaveKind(indexType, TypeFlags.NumberLike) || isForInVariableForNumericPropertyNames(node.argumentExpression)) {
const numberIndexType = getIndexTypeOfType(objectType, IndexKind.Number);
if (numberIndexType) {
return numberIndexType;
@ -8681,7 +8688,9 @@ namespace ts {
// Fall back to any.
if (compilerOptions.noImplicitAny && !compilerOptions.suppressImplicitAnyIndexErrors && !isTypeAny(objectType)) {
error(node, Diagnostics.Index_signature_of_object_type_implicitly_has_an_any_type);
error(node, getIndexTypeOfType(objectType, IndexKind.Number) ?
Diagnostics.Element_implicitly_has_an_any_type_because_index_expression_is_not_of_type_number :
Diagnostics.Index_signature_of_object_type_implicitly_has_an_any_type);
}
return anyType;

View file

@ -2422,6 +2422,10 @@
"category": "Error",
"code": 7013
},
"Element implicitly has an 'any' type because index expression is not of type 'number'.": {
"category": "Error",
"code": 7015
},
"Property '{0}' implicitly has type 'any', because its 'set' accessor lacks a type annotation.": {
"category": "Error",
"code": 7016