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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.