I was reading through typescript docs and came through this code excerpt:
type Mapish = { [k: string]: boolean };
type M = keyof Mapish;
and they gave the following explanation:
Note that in this example, M is string | number — this is because JavaScript object keys are always coerced to a string, so obj[0] is always the same as obj["0"].
so my question is why number
exclusively? why not boolean
or object
?
CodePudding user response:
TypeScript supports string
and number
index signatures, and (starting with TypeScript 4.4) symbol
and pattern template literal index signatures. Objects in JavaScript only really have string
and symbol
keys, so the string
, symbol
, and pattern template literal (which are a subtype of string
) index signatures in TypeScript should make perfect sense. But what's with number
?
Numeric index signatures are specifically intended to support arrays and other arraylike objects. It would be very annoying if indexing into an array with a numeric index produced a TypeScript error:
const arr = ["a", "b", "c"];
for (let i = 0; i < arr.length; i ) {
console.log(arr[i].toUpperCase());
// -----------> ~ <-- error, you can't index with a number?
}
Requiring non-idiomatic JavaScript like arr[String(i)]
would be inconvenient. And it wouldn't even help; the compiler can't really tell the difference between String(1)
and any other string, so it wouldn't understand that arr[String(1)]
should be an element of the array, as opposed to a method like arr["pop"]
.
So even though objects don't really have number
-valued keys, TypeScript pretends that they do in order to support arrays more naturally, because arrays are very commonly used with numeric indices in idiomatic JavaScript code.
On the other hand, nobody indexes into JavaScript objects with other objects, or with boolean
keys:
// nobody does this
const foo = { true: 1, false: 0, "[object Object]": 2 };
console.log(foo[Math.random() < 0.5]) // what
console.log(foo[{ a: 123 }]); // what are you doing
Well, maybe not nobody, but it is so rare that code like foo[false]
or foo[{}]
is much more likely to be a programming mistake than intended code. So TypeScript has no reason to allow boolean
or object
index signatures.