Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 992
iberbeu Avatar asked Oct 17 '16 12:10

iberbeu


People also ask

Are TypeScript enums ordered?

TypeScript defines the numeric value of an enum's member based on the order of that member that appears in the enum definition. For example, Jan takes 0, Feb gets 1, etc. In this example, the Jan constant value takes 1 instead of 0. The Feb takes 2, and the Mar takes 3, etc.

How do you sort an enum?

We can use the natural sort order or sort by their properties. Any Enum type we create implements the Comparable interface. Below is an excerpt from the Java documentation. Enum<E> implements Comparable<E> via the natural order of the enum (the order in which the values are declared).

Are constants allowed in enum?

An enum type is a special data type that enables for a variable to be a set of predefined constants. The variable must be equal to one of the values that have been predefined for it.

Can we change enum values in TypeScript?

You can always use a type assertion: // typescript enum example enum foo { ONE = 1, TWO = 2, THREE = 3 } (foo as any).


2 Answers

Had the same problem just now. This is my solution:

enum Weekday {
  MONDAY = 'MONDAY',
  TUESDAY = 'TUESDAY',
  WEDNESDAY = 'WEDNESDAY',
  THURSDAY = 'THURSDAY',
  FRIDAY = 'FRIDAY',
  SATURDAY = 'SATURDAY',
  SUNDAY = 'SUNDAY'
}

const weekdayOrder = Object.values(Weekday);

const weekdaysToBeSorted = [Weekday.TUESDAY, Weekday.MONDAY, Weekday.FRIDAY];

const sortedWeekdays = weekdaysToBeSorted
  .sort((a, b) => weekdayOrder.indexOf(a) - weekdayOrder.indexOf(b))
like image 121
Ricki-BumbleDev Avatar answered Oct 10 '22 09:10

Ricki-BumbleDev


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.

like image 45
Nitzan Tomer Avatar answered Oct 10 '22 08:10

Nitzan Tomer