You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
The type of a variable declared in a for-in statement is implicitly string (previously it was any).
When an object with a numeric index signature of type T (such as an array) is indexed by a for-in variable of a containing for-in statement for an object with a numeric index signature and without a string index signature (again such as an array), the value produced is of type T.
An example:
vara: MyObject[];for(varxina){// Type of x is implicitly stringvarobj=a[x];// Type of obj is MyObject}
With this PR, the type of x is now string and the type of obj is MyObject because the array is indexed with a for-in variable for an array (and thus the for-in variable is known to contain a numeric string). Had the array been indexed with any other string expression, the type of obj would be any because the string could be the name of a property or method (e.g. "length" or "push").
For historical reasons we have used type any for for-in variables even though the iterated values are always strings. The reason we used type any is that when an array is indexed with an expression of type any or number we produce a value of the array element type, and thus the example above produces the correct type for obj. However, with the second new rule above, indexing with an expression of type string can now also produce a value of the array element type if the expression is a for-in variable for an array.
The use of type any was never a great solution, in particular because the any is "silent" and not caught by the -noImplicitAny flag. Furthermore, with the introduction of the new for-of statement in ES2015 it got worse. Consider:
vara: MyObject[];for(varxina){// Accidentally used for-in instead of for-ofx.myObjectMethod();// Reports an error now, but didn't before}
This PR is a breaking change for certain (suspicious) constructs. For example:
vara: MyObject[];for(varxina){if(x==1){// Previously ok, now an error// ...}}
Previously, the static type of x was of type any. Thus, even though x contains a string it could be compared to a numeric literal (at run-time this coerces the string operand to a number and then compares that to the numeric operand). This is one of the not so good parts of JavaScript. Mixing of strings and numbers only work for some operators and are a source of many a surprising bug (for example, it doesn't work with the === operator, and + concatenates string values instead of adding the numeric values).
The reason will be displayed to describe this comment to others. Learn more.
Actually, I realized it's partially because you might have multiple variable declarations. But in that case, you'll have gotten an error on inconsistent types between the two variables anyway, so maybe it doesn't matter.
The reason will be displayed to describe this comment to others. Learn more.
Several reasons we need to climb up. Multiple declarations is one, making sure we're actually within a for-in statement is another, supporting for-in that references a variable instead of declaring one is a third.
After looking at some real-world code I've changed the test for an "array-like" object to be an object that has a numeric index signature and has no string index signature (as we originally contemplated). I found several instances of the following pattern:
varfooMap: {[x: number]: Foo}={};// ...for(variinfooMap){varfoo=fooMap[i];// Expect type of foo to be Foo// ...}
With the latest changes we'll assume that a for-in variable for an object with a numeric index signature and without a string index signature will iterate over a sequence of numeric property names, and when such a variable is used to index an object, the numeric index signature applies.
Also, I've added a better error message for the case where an object with a numeric index signature is indexed with a non-numeric value (such as a string). See the latest baseline changes for examples.
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR fixes #6346 by implementing two changes:
string
(previously it wasany
).An example:
With this PR, the type of
x
is nowstring
and the type ofobj
isMyObject
because the array is indexed with a for-in variable for an array (and thus the for-in variable is known to contain a numeric string). Had the array been indexed with any other string expression, the type of obj would beany
because the string could be the name of a property or method (e.g. "length" or "push").For historical reasons we have used type
any
for for-in variables even though the iterated values are always strings. The reason we used typeany
is that when an array is indexed with an expression of typeany
ornumber
we produce a value of the array element type, and thus the example above produces the correct type forobj
. However, with the second new rule above, indexing with an expression of typestring
can now also produce a value of the array element type if the expression is a for-in variable for an array.The use of type
any
was never a great solution, in particular because theany
is "silent" and not caught by the-noImplicitAny
flag. Furthermore, with the introduction of the new for-of statement in ES2015 it got worse. Consider:This PR is a breaking change for certain (suspicious) constructs. For example:
Previously, the static type of
x
was of typeany
. Thus, even thoughx
contains a string it could be compared to a numeric literal (at run-time this coerces the string operand to a number and then compares that to the numeric operand). This is one of the not so good parts of JavaScript. Mixing of strings and numbers only work for some operators and are a source of many a surprising bug (for example, it doesn't work with the===
operator, and+
concatenates string values instead of adding the numeric values).