3

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 */

2 Answers 2

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 :)

Sign up to request clarification or add additional context in comments.

Comments

0

Short answer:

Only numeric enums can have computed 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'}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.