Home > Software engineering >  keyof type operator with indexed signature
keyof type operator with indexed signature

Time:05-22

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.


Playground link to code

  • Related