iberbeu iberbeu - 1 month ago 12
TypeScript Question

Typescript Sorting based on Enum constants

Is it possible to have a list of enums sorted by the order these enums were declared?

enum MyEnum {
VALUE_1,
VALUE_3,
VALUE_2
}


I create a list in a random order

let list = [MyEnum.VALUE_3, MyEnum.VALUE_1, MyEnum.VALUE_2];


But it gets ordered as the enum was declared

[MyEnum.VALUE_1, MyEnum.VALUE_3, MyEnum.VALUE_2]


PS: I really want to know if typescript orders the list out of the box as we have in Java, without having to order it by my own. If I had to order the list by my own I would be prone to errors if the order ever gets changed.

Answer

If you look at the compiled javascript of your enum:

var MyEnum;
(function (MyEnum) {
    MyEnum[MyEnum["VALUE_1"] = 0] = "VALUE_1";
    MyEnum[MyEnum["VALUE_3"] = 1] = "VALUE_3";
    MyEnum[MyEnum["VALUE_2"] = 2] = "VALUE_2";
})(MyEnum || (MyEnum = {}));

You'll see that each gets an ordinal number based on the position, so the first is 0 and the last is 2.

If you refer to an enum you'll just get a number back:

console.log(MyEnum.VALUE_3); // 1

If you want to sort your list:

let list = [MyEnum.VALUE_3, MyEnum.VALUE_1, MyEnum.VALUE_2];
console.log(list); // [1, 0, 2]
list.sort((a, b) => a - b);
console.log(list); // [0, 1, 2]

If you want the list of the string names of the enum sorted by the ordinal then you can do:

let names = list.map(ordinal => MyEnum[ordinal]);
console.log(names); // ["VALUE_1", "VALUE_3", "VALUE_2"]

(code in playground)


Edit

You can sort in the same way, regardless of how you set the enum values, you just need to change the compare function.
For example, this will sort the list based on the lexicographical order of the enum string values:

enum MyEnum {
    VALUE_1 = "value 1" as any,
    VALUE_3 = "value 3" as any,
    VALUE_2 = "value 2" as any
}

let list = [MyEnum.VALUE_3, MyEnum.VALUE_1, MyEnum.VALUE_2];
console.log(list); // ["value 3", "value 1", "value 2"]
list.sort((a, b) => {
    if (a < b) return -1;
    if (a > b) return 1;
    return 0;
});
console.log(list); // ["value 1", "value 2", "value 3"]

let names = list.map(ordinal => MyEnum[ordinal]);
console.log(names); // ["VALUE_1", "VALUE_2", "VALUE_3"]

(code in playground)


Edit #2

Sorting by the original order of the enum is tricky, you can try:

enum MyEnum {
    VALUE_1 = "value 1" as any,
    VALUE_3 = "value 3" as any,
    VALUE_2 = "value 2" as any
}

let list = [MyEnum.VALUE_3, MyEnum.VALUE_1, MyEnum.VALUE_2];
console.log(list); // ["value 3", "value 1", "value 2"]

let sorted = [] as MyEnum[];
let index = 0;
for (let key in MyEnum) {
    if (index % 2 === 0) {
        sorted.push(key as any);
    }

    index++;
}

console.log(sorted); // ["VALUE_1", "VALUE_3", "VALUE_2"]

let names = sorted.map(ordinal => MyEnum[ordinal]);
console.log(names); // ["value 1", "value 3", "value 2"]

(code in playground)

This seems to work, but you shouldn't count on the order which is received in the for/in loop, unless you don't care about cross-browser behavior (or to be specific explorer support), you can read about it in MDN.

Comments