Žilvinas Rudžionis
Žilvinas Rudžionis

Reputation: 2346

How to create union type from enum numeric values?

From enum:

enum Weekdays {
  Monday = 1,
  Tuesday = 2
}

We would like to get this type:

type WeekdaysType = 1 | 2

Upvotes: 2

Views: 823

Answers (4)

jfMR
jfMR

Reputation: 24738

If, instead of the numeric enum, you create a const object whose prototypes correspond to the numeric values your original enum had:

const Weekdays = {
  Monday: 1,
  Tuesday: 2,
} as const;

Then, you can define a type with the same name as the object above:

type Weekdays = (typeof Weekdays)[keyof typeof Weekdays];

This type is the union of the types of the object properties, i.e., 1 | 2. That's why you need the as const assertion above so that TypeScript infers the literal types 1 and 2 for Monday and Tuesday, respectively. Otherwise, it would infer the broader type number and the type Weekdays would result in number as a consequence.

Both typeofs aren't JavaScript's typeof despite taking a value (i.e., the const object) as their operand. They correspond to TypeScript's typeof because they are being used in the type space (they are inside a type definition):

type Weekdays = (typeof Weekdays)[keyof typeof Weekdays];
                 ^^^^^^                 ^^^^^^

Finally, note that in this solution, you have both a type and a value with the name Weekdays: the type Weekdays and the const object Weekdays. There are no clashing issues here since they live in different spaces: the type and value spaces.

Upvotes: 1

Barry Song
Barry Song

Reputation: 1

enum Code {
    a = 111,
    b = 222,
    c = 'abc'
}

type StrToNum<Str> =
  Str extends `${infer Num extends number}`
    ? Num
    : Str

type res = StrToNum<`${Code}`>;

Upvotes: 0

shaell
shaell

Reputation: 29

Instead enum, you can use union types

const Weekdays {
  Monday: 1,
  Tuesday: 2,
} as const;

type Union<T> = T[keyof T];

type WeekdaysType = Union<typeof Weekdays>; // type WeekdaysType = 1 | 2

// you can use like enum
console.log(Weekdays.Monday) // 1

Numeric enums are not type safe

enum ZeroOrOne {
  Zero = 0,
  One = 1
}
const zeroOrOne: ZeroOrOne = 2; // no error!!

Upvotes: -1

Luke Carr
Luke Carr

Reputation: 571

With TypeScript 4.1+, you can use template literal types:

enum Weekdays {
  Monday = 1,
  Tuesday = 2,
};

type WeekdaysType = `${Weekdays}`;

Caveat: This only works with enums that have string values, so for your particular use case, WeekdaysType would be "1" | "2", rather than 1 | 2. As far as I'm aware, there's no current way to dynamically extract numeric enum values into a union type.

TypeScript Playground

Upvotes: 0

Related Questions