I'd like to get a string literal union from an enum.
For this enum…
enum Weekday { MONDAY = 'mon', TUESDAY = 'tue', WEDNESDAY = 'wed' }
… I'd like to get this:
type WeekdayType = 'mon' | 'tue' | 'wed';
I tried typeof keyof Weekday
but that resulted in 'MONDAY' | 'TUESDAY' | 'WEDNESDAY'
. Feel like the solution might have to do with mapped types but I can't seem to wrap my head around it.
How do I do this?
Use a template literal type to convert an enum to a union type, e.g. type ValuesUnion = ${StringEnum} . Template literal types have the same syntax as template literal strings. The union type will contain all of the values of the enum.
Enums or enumerations are a new data type supported in TypeScript. Most object-oriented languages like Java and C# use enums. This is now available in TypeScript too. In simple words, enums allow us to declare a set of named constants i.e. a collection of related values that can be numeric or string values.
With the recent versions of TypeScript, it is easy to declare iterable union types. Therefore, you should prefer union types to enums.
The they are useless at runtime argument This is a false argument for typescript in general, let alone Enums. and agree, if at runtime some code tries to change the values of one of your enums, that would not throw an error and your app could start behaving unexpectedly ( that is why Object.
See TS4.1 ANSWER:
type WeekdayType = `${Weekday}`;
PRE TS-4.1 ANSWER:
This can't be done programmatically... you're trying to convert the type Weekday
, which is Weekday.MONDAY | Weekday.TUESDAY | Weekday.WEDNESDAY
, to the type WeekdayType
which is "mon" | "tue" | "wed"
. This conversion is a form of widening, since Weekday
is a subtype of WeekdayType
:
type WeekdayExtendsWeekdayType = Weekday extends WeekdayType ? true : false // type WeekdayExtendsWeekdayType = true
Unfortunately the compiler doesn't give you a handle to remove an "enum"-ness from the enum type and leave you with plain literal types.
So, workarounds? Maybe you don't actually need an enum
, but can make do with an object whose property values are string literals:
const lit = <V extends keyof any>(v: V) => v; const Weekday = { MONDAY: lit("mon"), TUESDAY: lit("tue"), WEDNESDAY: lit("wed") } type Weekday = (typeof Weekday)[keyof typeof Weekday],
If you inspect it, the value named Weekday
behaves like an enum object:
console.log(Weekday.TUESDAY); // tue
while the type named Weekday
behaves like the union of string values "mon" | "tue" | "wed"
that you were calling WeekdayType
:
const w: Weekday = "wed"; // okay const x: Weekday = "xed"; // error
So in this workaround, there is no "enum"-ness, and therefore no need to distinguish the type Weekday
from the type WeekdayType
. It's a little different from an actual enum
(which includes types like Weekday.MONDAY
, which you'd have to represent as the cumbersome typeof Weekday.MONDAY
or create a different type alias for it), but it might behave similarly enough to be useful. Does that work for you?
Hope that helps. Good luck!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With