Say, I have an array const colors = ['R', 'G', 'B']
(or object const colors = {R: 'R', G: 'G', B: 'B'}
which will also do). Considering typescript enums transpiled into objects, if I'm not missing anything. Is there a way to parse above array (or object) into enum dynamically?
E.g. something like (non-working pseudo-code sample for the sake of example):
type Color = colors.reduce((palette, color) => palette | color)
or
enum Color = colors.reduce((palette, color) => (palette[color] = color, palette), enum)
The whole idea behind is to turn long list of string values into enum, without hardcoding miles long type definition, like:
type Color = 'R' | 'G' | 'B' .. /* followed by gazillion more color values */
Say, I have an array const colors = ['R', 'G', 'B']
(or object const colors = {R: 'R', G: 'G', B: 'B'}
which will also do). Considering typescript enums transpiled into objects, if I'm not missing anything. Is there a way to parse above array (or object) into enum dynamically?
E.g. something like (non-working pseudo-code sample for the sake of example):
type Color = colors.reduce((palette, color) => palette | color)
or
enum Color = colors.reduce((palette, color) => (palette[color] = color, palette), enum)
The whole idea behind is to turn long list of string values into enum, without hardcoding miles long type definition, like:
type Color = 'R' | 'G' | 'B' .. /* followed by gazillion more color values */
Share
Improve this question
asked Nov 20, 2020 at 18:33
Curr195Curr195
1331 silver badge5 bronze badges
2 Answers
Reset to default 5I think you need something like this:
const Colors = ['Red', 'Blue', 'Green'] as const;
type colors = typeof Colors[number] // 'Red' | 'Blue' | 'Green'
Hopefully, this will work for you :)
Short answer:
Only numeric enums can have puted members, but this expression has type 'string'. If you do not need exhaustiveness checks, consider using an object literal instead`.
The long answer:
Unfortunately, you can do it, but it does not mean you should:
const colors = ['R', 'G', 'B']
enum Color { }
const result = colors.reduce((acc, elem) => {
return {
...acc,
[elem]: elem
}
}, Color)
In this case, you are loosing type safety. TS, can not figure out type of Color enum.
type O = keyof typeof result // never, TS don't know anymore nothing about this type
enum OkColor{
R='R',
G='G',
B='B'
}
type O2 = keyof typeof OkColor // 'R' | 'G' | 'B' ---> here TS knows the keys of enum
Try to avoid enums
as much as possible.
The best approach is to use constant objects:
const colors = {
R:'R',
G: 'G',
B: 'B',
} as const;
If you still want to use enums, use them at least with const
keyword. See docs
const enum X {
A='A'
}
Here is code for type safe converting an array to readonly object:
const colors = ['R', 'G', 'B'] as const;
type ValuesOfArray<T extends ReadonlyArray<any>> = T[number]
type ToObj<K extends string> = {
[P in K]: P
}
type ToEnum = ToObj<ValuesOfArray<typeof colors>>
const toPseudoEnum = <T extends readonly any[], K extends ValuesOfArray<T>>(arr: T):Readonly<ToObj<K>> => {
return arr.reduce((acc, elem) => {
return {
...acc,
[elem]: elem
}
}, {})
}
const customEnum = toPseudoEnum(colors); // {R:'R',G:'G',B:'B'}