@@ -2520,9 +2520,9 @@ namespace ts {
2520
2520
2521
2521
// Return the inferred type for a variable, parameter, or property declaration
2522
2522
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
2524
2524
if (declaration.parent.parent.kind === SyntaxKind.ForInStatement) {
2525
- return anyType ;
2525
+ return stringType ;
2526
2526
}
2527
2527
2528
2528
if (declaration.parent.parent.kind === SyntaxKind.ForOfStatement) {
@@ -8563,6 +8563,23 @@ namespace ts {
8563
8563
return true;
8564
8564
}
8565
8565
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
+
8566
8583
function checkIndexedAccess(node: ElementAccessExpression): Type {
8567
8584
// Grammar checking
8568
8585
if (!node.argumentExpression) {
@@ -8623,7 +8640,7 @@ namespace ts {
8623
8640
if (isTypeAnyOrAllConstituentTypesHaveKind(indexType, TypeFlags.StringLike | TypeFlags.NumberLike | TypeFlags.ESSymbol)) {
8624
8641
8625
8642
// Try to use a number indexer.
8626
- if (isTypeAnyOrAllConstituentTypesHaveKind(indexType, TypeFlags.NumberLike)) {
8643
+ if (isTypeAnyOrAllConstituentTypesHaveKind(indexType, TypeFlags.NumberLike) || isForInVariableForArrayLikeObject(node.argumentExpression) ) {
8627
8644
const numberIndexType = getIndexTypeOfType(objectType, IndexKind.Number);
8628
8645
if (numberIndexType) {
8629
8646
return numberIndexType;
@@ -12697,7 +12714,8 @@ namespace ts {
12697
12714
}
12698
12715
// For a binding pattern, validate the initializer and exit
12699
12716
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) {
12701
12719
checkTypeAssignableTo(checkExpressionCached(node.initializer), getWidenedTypeForVariableLikeDeclaration(node), node, /*headMessage*/ undefined);
12702
12720
checkParameterInitializer(node);
12703
12721
}
@@ -12707,7 +12725,8 @@ namespace ts {
12707
12725
const type = getTypeOfVariableOrParameterOrProperty(symbol);
12708
12726
if (node === symbol.valueDeclaration) {
12709
12727
// 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) {
12711
12730
checkTypeAssignableTo(checkExpressionCached(node.initializer), type, node, /*headMessage*/ undefined);
12712
12731
checkParameterInitializer(node);
12713
12732
}
0 commit comments