When comparing { [key: string]: any }
and { [key: number]: any }
, it is important to note that they define different sets of keys. Just because you can assign y = x
, it doesn't necessarily mean that the types of those variables are identical. This simply indicates that they are "compatible" or "assignable". If you can assign x = y
, then we can say that y
is assignable to x
(or the type of y
is assignable to the type of x
). Often, this implies that y
is a subtype of x
. Therefore, { [key: string]: any }
can be assigned to { [key: number]: any }
. But why? What does { [k: K]: V }
actually mean?
An index signature in the form of {[k: K]: V}
does not require every property key to be of type K
. It simply enforces that if a key is of type K
, then the corresponding value must be of type
V</code. This specification does not address how keys of other types should be handled. TypeScript's <a href="https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html#structural-type-system" rel="nofollow noreferrer">structural type system</a> generally allows for "extra" or "excess" properties, <a href="https://www.typescriptlang.org/docs/handbook/release-notes/typescript-1-6.html#stricter-object-literal-assignment-checks" rel="nofollow noreferrer">with exceptions involving object literals</a>.</p>
<p>Therefore, <code>{ [key: number]: any}
specifies that all property keys of type
number
* will have values of type
any
. You can access such an object with any numeric key. However, this declaration does not restrict keys like
"hi"
. Hence, an object of this type could potentially contain a key like
"hi"
. The following assignment would succeed:
let x: { [key: string]: any } = { 'hi': 'bye' };
let y: { [key: number]: any } = x; // valid
Despite this assignment, attempting to index into y
with a non-number
key will trigger a compiler error since the type of y
cannot predict what lies behind such a key:
y[1]; // valid
y.hi; // error
If you try to directly assign {hi: "bye"}
as an object literal to y
, it will fail due to excess property checking:
y = { 'hi': 'bye' }; // error;
This failure does not imply that {hi: "bye"}
is incompatible with the type of y</code (since <code>y = x
works). Instead, it signals a potential developer mistake, as after assigning y = { hi: "bye" }
, the compiler no longer recognizes the hi
key when accessing y.hi
. In contrast, y = x
avoids this issue by retaining access to the hi
key provided by x
.
Playground link to code
* In JavaScript, there aren't keys of type number
; rather, there are numeric strings like "0"
and "1"
. TypeScript treats them as numbers for ease of iteration over arrays with numerical indices.