Today I have spent quite a few hours trying to contribute a P.R. to a project I really like, and often use in my day-to-day work, the excellent class-validator. The problem I was trying to solve consisted in listing the possible values for a given enum, in order to let class-validator print them in its enum-related error messages.
The main problem is that enums get transpiled differently, based on their contents and the way they're declared.
When values are not specified, an incremental integer is assigned to each key, so the transpiled JS looks like the following:
// Before
enum Steak {
Medium,
Rare,
WellDone
}
// After
var Steak;
(function (Steak) {
Steak[Steak["Medium"] = 0] = "Medium";
Steak[Steak["Rare"] = 1] = "Rare";
Steak[Steak["WellDone"] = 2] = "WellDone";
})(Steak || (Steak = {}));
When an integer number is assigned as the value, it is simply assigned instead of the default incremental integer in the example before.
// Before
enum Steak {
Medium = 10,
Rare = 20,
WellDone = 30
}
// After
var Steak;
(function (Steak) {
Steak[Steak["Medium"] = 10] = "Medium";
Steak[Steak["Rare"] = 20] = "Rare";
Steak[Steak["WellDone"] = 30] = "WellDone";
})(Steak || (Steak = {}));
When a string value is assigned, though, the transpiled JS code looks a bit different:
// Before
enum Steak {
Medium = "MEDIUM",
Rare = "RARE",
WellDone = "WELL_DONE"
}
// After
var Steak;
(function (Steak) {
Steak["Medium"] = "MEDIUM";
Steak["Rare"] = "RARE";
Steak["WellDone"] = "WELL_DONE";
})(Steak || (Steak = {}));
These transpilation differences lead to obvious inconsistencies when attempting to retrieve an enum's list of possible values when using the common Object.values(), Object.keys() and Object.entries() methods. By fiddling with an heterogeneous enum like the following:
// Before
enum TestEnum {
a = 'aA',
b = 'bB',
c = 1,
d = 2,
e = '01'
}
// After
var TestEnum;
(function (TestEnum) {
TestEnum["a"] = "aA";
TestEnum["b"] = "bB";
TestEnum[TestEnum["c"] = 1] = "c";
TestEnum[TestEnum["d"] = 2] = "d";
TestEnum["e"] = "01";
})(TestEnum || (TestEnum = {}));
The following conclusions can be drawn:
So, finally, the solution I came up with is:
Object.entries(TestEnum).filter(entry => !parseInt(entry[0])).map(entry => entry[1])
Which starts from Object.keys()'s results, filtering out all the redundant [value, key] entries.