0

Is there any way to tell Typescript that I have an array that will be indexed by a given numeric enum? For example I might have this code:

enum Animals {
  dog,
  bear,
  cat,
}

const animalColours: string[] = [
  "black",
  "brown",
  "white",
];

But if I add an extra animal type I can easily forget to update animalColours, which leads to a runtime error. An improvement is to use Record:

enum Animals {
  dog,
  bear,
  cat,
}

const animalColours: Record<Animals, string> = {
  [Animals.dog]: "black",
  [Animals.bear]: "brown",
  [Animals.cat]: "white",
};

Typescript will then detect if I miss any variants. However I do not want to use a Record for various reasons that I won't go into here. Is there any way to achieve the same thing with an array? The best I can come up with is to convert the Record at runtime, but that sucks because it has a runtime cost, especially because you have to sort them (iteration order isn't guaranteed).

const animalColoursRecord: Record<Animals, string> = {
  [Animals.dog]: "black",
  [Animals.bear]: "brown",
  [Animals.cat]: "white",
};

// In fact this doesn't even work because Object.entries() always returns
// [string; string][].
const animalColours: string[] = Object.entries(animalColoursRecord).sort((a, b) => a[0] > b[0]).map(x => x[1])

It also means Typescript won't complain about animalColours[10].

Is there a way to get the type safety of Record<T, U> but using arrays?

Timmmm
  • 88,195
  • 71
  • 364
  • 509
  • 1
    This essentially https://stackoverflow.com/questions/55127004/how-to-transform-union-type-to-tuple-type, the union in your case is `keyof typeof Animals`. The answer is you might be able to do it but it not very robust. – ccarton Aug 28 '20 at 12:02
  • Not the same question at all. That one doesn't even involve enums. – Timmmm Aug 30 '20 at 13:26
  • The solution is 95% the same. The only difference is that you need one extra step to first convert your enum to a union which is: `type AnimalUnion = keyof typeof Animals` – ccarton Aug 30 '20 at 13:34
  • The output isn't even the same. That answer produces an array of the possible enum values. I want an array that can be *indexed* by the enum. – Timmmm Aug 30 '20 at 17:04
  • Ah, apologies, I misread. So then, what kind of safety do you expect other than a constraint on the length? Do you have an example of code that you want to error? – ccarton Aug 30 '20 at 18:27
  • I think the answer might still be similar to that other question. You just need the types in the tuple to be `string` rather than the enum values. Is that accurate? – ccarton Aug 30 '20 at 19:46
  • No I want the enum types to be integers so that they can index the array! And ideally I want it to give me an error if it can't prove that the index type is my enum, so `animalColors[10]` would be an error as I said in the question. – Timmmm Aug 31 '20 at 07:59
  • It would be nice if `animalColors[0]` was also an error but I can live without that. – Timmmm Aug 31 '20 at 08:01

0 Answers0