1

Let's say I have a simple enum

enum MyEnum {
  a,
  b,
  c
}

Mapping the enum into a key value const is simple:

type A<V> = { [k in MyEnum]: V };

const testA: A<string> = { 
  [MyEnum.a]: '',
  [MyEnum.b]: '',
  [MyEnum.c]: ''
};

The problem starts when I am trying to pass the enum as a generic type:

type B1<T, V> = { [k in T]: V } // that won't work
const testB: A<MyEnum , string> = { ... } // usage

I tried few approaches ideas in this play-ground

There are some similar question (listed bellow) but I still got the feeling that in this particular example if the first option (type A<V> = { [k in MyEnum]: V };) is possible the other options should be too (type B1<T, V> = ).

Mapping Enum to Type of keys or values

is-it-possible-to-allow-literal-string-values-with-typescripts-enum-type

Natan Braslavski
  • 819
  • 8
  • 18
  • 2
    For what it's worth, I think a correct version of your type is [the built in `Record` type.](https://www.typescriptlang.org/docs/handbook/utility-types.html#recordkeys-type) `Record` works like you expect. `Record` is simply: `type Record = { [P in K]: T; }` – Alex Wayne Mar 18 '22 at 23:41
  • @AlexWayne Good observation, I completely missed that! – Oblosys Mar 19 '22 at 02:11

1 Answers1

2

The error message on type B1<T, V> = { [k in T]: V } says Type 'T' is not assignable to type 'string | number | symbol'., which can be remedied by adding a constraint to T:

type B<T extends PropertyKey, V> = { [k in T]: V }

(using the built-in type PropertyKey = string | number | symbol)

Now you can pass the enum to B as a generic argument:

const testB: B<MyEnum, string> = {
  [MyEnum.a]: 'aa',
  [MyEnum.b]: 'bb',
  [MyEnum.c]: 'cc'
};

TypeScript playground

Or, as Alex Wayne suggested, you can forego declaring B altogether and just use the built-in Record type. It's definition is

type Record<K extends keyof any, T> = {[P in K]: T}

which is equivalent to B, as keyof any is string | number | symbol, just like PropertyKey.

Oblosys
  • 14,468
  • 3
  • 30
  • 38