Natan Braslavski
Natan Braslavski

Reputation: 849

mapping enum to a key value (with generics)

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

Upvotes: 1

Views: 306

Answers (1)

Oblosys
Oblosys

Reputation: 15106

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.

Upvotes: 2

Related Questions