Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to build a type from enum values in TypeScript?

Given the following:

enum FooKeys {   FOO = 'foo',   BAR = 'bar', } 

I'd like to make an interface like this one, but instead of defining keys by hand, build it out of enum's values.

interface Foo {   foo: string   bar: string } 

Is something like this possible with TypeScript?

Thanks!

like image 471
moltar Avatar asked Mar 13 '19 12:03

moltar


People also ask

Can I use enum as a type in TypeScript?

Enums or enumerations are a new data type supported in TypeScript. Most object-oriented languages like Java and C# use enums. This is now available in TypeScript too. In simple words, enums allow us to declare a set of named constants i.e. a collection of related values that can be numeric or string values.

Can enum be a type?

An enum type is a special data type that enables for a variable to be a set of predefined constants.

What is difference between type and enum in TypeScript?

Enums allow us to define or declare a collection of related values that can be numbers or strings as a set of named constants. Unlike some of the types available in TypeScript, enums are preprocessed and are not tested at compile time or runtime.

What does TypeScript enum compile to?

Enums in TypeScript isn't only a compile-time feature. The enum type does actually gets compiled into a JavaScript object. This program when compiled produces the following output.


2 Answers

Yes, you can use enum values as keys. And you can use a mapped type like the standard library's Record<K, V> to prevent repetition:

enum FooKeys {   FOO = 'foo',   BAR = 'bar', }  // probably all you need, but it's a type alias type FooType = Record<FooKeys, string>;  // if you need an interface instead you can do this interface FooInterface extends FooType {}; 

And you can verify that it works:

declare const foo: FooInterface; foo.foo; // okay foo[FooKeys.FOO]; // okay  foo.bar; // okay foo[FooKeys.BAR]; // okay  foo.baz; // error 

Does that work for you? Good luck!

like image 50
jcalz Avatar answered Sep 28 '22 07:09

jcalz


@hackape 's solution is great, but I found minimal duplication extending his solution as below:

type ReverseMap<T extends Record<keyof T, any>> = {   [V in T[keyof T]]: {     [K in keyof T]: T[K] extends V ? K : never;   }[keyof T]; }  const Map = {   'FOO': "foo" as "foo",   'BAR': "bar" as "bar", }  const reverseMap: ReverseMap<typeof Map> = Object.entries(Map).reduce((rMap, [k, v]) => {   rMap[v] = k;   return rMap; }, {} as any);  export type Values = keyof typeof reverseMap; // 'foo' | 'bar'; 

ReverseMap implementation is well explained here

like image 31
Akash Babu Avatar answered Sep 28 '22 07:09

Akash Babu