最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Convert array of strings into enum - Stack Overflow

programmeradmin3浏览0评论

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
Add a ment  | 

2 Answers 2

Reset to default 5

I 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'}
发布评论

评论列表(0)

  1. 暂无评论