Is object[number] now legal in 0.9?

Topics: Language Specification
Jul 2, 2013 at 11:00 PM
Hello everyone, I've been using 0.9 for a few days now, and man! Fantastic! Generics are a great addition to the language, especially since I'm writing a lot of Knockout code.

I use a fair number of associative arrays in my code, with definitions like:
interface LocationItemById { [locationId: string]: LocationItem; }
The id fields are actually numbers, but, well, you know, JavaScript.

Anyway, in TypeScript 0.8, I had a lot of code that looked like
var location = this.locations[locationId.toString()];
But in TypeScript 0.9, it seems that this is now accepted:
var location = this.locations[locationId];
I like the convenience, but the 0.8 behavior seemed to be more "correct" -- it always reminded me that JavaScript objects use string keys, period. And I feel uneasy that I can index by number when I declared the indexer as a string type...

Was this change intentional?
Developer
Jul 3, 2013 at 12:07 AM
Yes, this is intentional. You can see the rules for resolving property accesses in section 4.10 Property Access of the language spec. Relevant part here:
A bracket notation property access of the form
ObjExpr [ IndexExpr ]
where ObjExpr and IndexExpr are expressions, is used to access the property with the name computed by the index expression on the given object. A bracket notation > property access is processed as follows at compile-time:
• If IndexExpr is a string literal or a numeric literal and ObjExpr is of a type that has a property with the name given by that literal (converted to its string representation in the case of a numeric literal), the property access is of the type of that property.
• Otherwise, if ObjExpr is of a type that has a numeric index signature and IndexExpr is of type Any, the Number primitive type, or an enum type, the property access is of the type of that index signature.
• Otherwise, if ObjExpr is of a type that has a string index signature and IndexExpr is of type Any, the String or Number primitive type, or an enum type, the property access is of the type of that index signature.
• Otherwise, if IndexExpr is of type Any, the String or Number primitive type, or an enum type, the property access is of type Any.
• Otherwise, the property access is invalid and a compile-time error occurs.
If I recall correctly this rule was introduced specifically for scenarios like yours where object literals use numbers as the names for fields and want to used in 'array-like' fashion without additional ceremony like using toString on every index expression.
Jul 11, 2013 at 6:15 PM
Thanks!
Jul 12, 2013 at 5:27 PM
I notice that in previous versions of TypeScript:
for (var x in obj)
x was of type string. But now in 0.9, x is of type any, and you can't even do something like:
for (var x: string in obj)
to help TypeScript out.

I can't find any section of the spec dealing with what the type of x should be in this construction. Surely it should always be a string? I mean, unless you wanted to do something clever like:
var obj: { [index: number]: number; } = { 1: 2 };
for (var x in obj)  // number is the best common type of all obj's defined index expressions, so the type of x is number