@@ -2520,9 +2520,9 @@ namespace ts {
25202520
25212521 // Return the inferred type for a variable, parameter, or property declaration
25222522 function getTypeForVariableLikeDeclaration(declaration: VariableLikeDeclaration): Type {
2523- // A variable declared in a for..in statement is always of type any
2523+ // A variable declared in a for..in statement is always of type string
25242524 if (declaration.parent.parent.kind === SyntaxKind.ForInStatement) {
2525- return anyType ;
2525+ return stringType ;
25262526 }
25272527
25282528 if (declaration.parent.parent.kind === SyntaxKind.ForOfStatement) {
@@ -8563,6 +8563,23 @@ namespace ts {
85638563 return true;
85648564 }
85658565
8566+ /**
8567+ * Return true if given node is an expression consisting of an identifier (possibly parenthesized)
8568+ * that references a variable declared in a for-in statement for an array-like object.
8569+ */
8570+ function isForInVariableForArrayLikeObject(node: Expression) {
8571+ const e = skipParenthesizedNodes(node);
8572+ if (e.kind === SyntaxKind.Identifier) {
8573+ const symbol = getResolvedSymbol(<Identifier>e);
8574+ if (symbol.flags & SymbolFlags.Variable) {
8575+ const parent = symbol.valueDeclaration.parent.parent;
8576+ return parent.kind === SyntaxKind.ForInStatement &&
8577+ isArrayLikeType(checkExpression((<ForInStatement>parent).expression));
8578+ }
8579+ }
8580+ return false;
8581+ }
8582+
85668583 function checkIndexedAccess(node: ElementAccessExpression): Type {
85678584 // Grammar checking
85688585 if (!node.argumentExpression) {
@@ -8623,7 +8640,7 @@ namespace ts {
86238640 if (isTypeAnyOrAllConstituentTypesHaveKind(indexType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbol)) {
86248641
86258642 // Try to use a number indexer.
8626- if (isTypeAnyOrAllConstituentTypesHaveKind(indexType, TypeFlags.NumberLike)) {
8643+ if (isTypeAnyOrAllConstituentTypesHaveKind(indexType, TypeFlags.NumberLike) || isForInVariableForArrayLikeObject(node.argumentExpression) ) {
86278644 const numberIndexType = getIndexTypeOfType(objectType, IndexKind.Number);
86288645 if (numberIndexType) {
86298646 return numberIndexType;
@@ -12697,7 +12714,8 @@ namespace ts {
1269712714 }
1269812715 // For a binding pattern, validate the initializer and exit
1269912716 if (isBindingPattern(node.name)) {
12700- if (node.initializer) {
12717+ // Don't validate for-in initializer as it is already an error
12718+ if (node.initializer && node.parent.parent.kind !== SyntaxKind.ForInStatement) {
1270112719 checkTypeAssignableTo(checkExpressionCached(node.initializer), getWidenedTypeForVariableLikeDeclaration(node), node, /*headMessage*/ undefined);
1270212720 checkParameterInitializer(node);
1270312721 }
@@ -12707,7 +12725,8 @@ namespace ts {
1270712725 const type = getTypeOfVariableOrParameterOrProperty(symbol);
1270812726 if (node === symbol.valueDeclaration) {
1270912727 // Node is the primary declaration of the symbol, just validate the initializer
12710- if (node.initializer) {
12728+ // Don't validate for-in initializer as it is already an error
12729+ if (node.initializer && node.parent.parent.kind !== SyntaxKind.ForInStatement) {
1271112730 checkTypeAssignableTo(checkExpressionCached(node.initializer), type, node, /*headMessage*/ undefined);
1271212731 checkParameterInitializer(node);
1271312732 }
0 commit comments