Nie jest tak, że w czystym JS w sensie funkcyjnym enumy nie występują – widzieliśmy je w node iteratorach i tree walkerach. W sensie składniowym jednak ich tam nie ma, więc pochylmy się nad tym zagadnieniem w TS.

Ok, enum to jest takie coś – argument funkcji może przyjąć np. 1, 0 i -1. Każda z tych liczb coś oznacza. Wewnątrz funkcji wykonuję sprawdzenie, czy mam 1,0 czy -1 i odpowiadam na to jakąś akcją.

I zarówno ja, tę funkcję piszący, i ktoś inny, tę funkcję czytający i jeszcze ktoś inny, używający tej funkcji, musi wiedzieć, co 1, 0 i -1 sobą reprezentują. To jest bardzo złe, nie chce już mi się tłumaczyć dlaczego.

Widzieliśmy to w sensie funkcyjnym w JS, tam robiono namespace + const. NodeFilter.REJECT, NodeFilter.ACCEPT i tak dalej. To jest po prostu nadanie jakiejś nazwy, która będzie wystarczająco zrozumiała.

Czy enumy w TS są dobre to inna kwestia, wielu uważa, że nie. Mniejsza o to. Znamy koncepcję, dzięki której dostajemy jakąś nazwę, np. NodeFilter.REJECT i my, piszący tę funkcję z tym porównujemy. Czytający tę funkcję to czyta i rozumie. Korzystający z tej funkcji to przekazuje. Tylko komputer wie, jaka wartość się pod tym kryje i że tak naprawdę to porównuje 0 z 0, na przykład.

To teraz zobaczmy jak od strony składni się tworzy enumy w TS:

enum Direction {
    Up,
    Down,
    Left,
    Right,
  }

Zobaczmy na coś takiego, bo enum to w zasadzie podobna rzecz:

enum Direction {
    Up,
    Down,
    Left,
    Right,
  }

type DirKeys = keyof typeof Direction;
//"Up" | "Down" | "Left" | "Right"

To tak jakby ten typ dopisać do tego. Ok, zobaczmy, co tu się dzieje:

enum Direction {
    Up,
    Down,
    Left,
    Right,
  }

function processDirection(dir: Direction){
    switch(dir){
        case Direction.Up:
            console.log("going up");
            break;
        case Direction.Down:
            console.log("going down");
            break;
        case Direction.Left:
            console.log("going left");
            break;
        case Direction.Right:
            console.log("going right");
            break;
        default:
            console.log("unknown direction");
            break;
    }
}

console.log(processDirection(Direction.Up)); //going up
console.log(processDirection(0)); //going up

Ok, jak mamy działające to zepsujmy i wtedy najlepiej zrozumiemy jak to działa:

enum Direction {
    Up = 0,
    Down = 1,
    Left = 2,
    Right = 3,
  }

function processDirection(dir: Direction){
    switch(dir){
        case 0:
            console.log("going up");
            break;
        case 1:
            console.log("going down");
            break;
        case 2:
            console.log("going left");
            break;
        case 3:
            console.log("going right");
            break;
        default:
            console.log("unknown direction");
            break;
    }
}

console.log(processDirection(Direction.Up)); //going up
console.log(processDirection(0)); //going up

Zaczynamy powoli rozumieć? To zepsujmy jeszcze bardziej:

enum Direction {
    Up = 0,
    Down = 1,
    Left = 2,
    Right = 3,
  }

function processDirection(dir: 0|1|2|3){
    switch(dir){
        case 0:
            console.log("going up");
            break;
        case 1:
            console.log("going down");
            break;
        case 2:
            console.log("going left");
            break;
        case 3:
            console.log("going right");
            break;
        default:
            console.log("unknown direction");
            break;
    }
}

console.log(processDirection(Direction.Up)); //going up
console.log(processDirection(0)); //going up

Zobaczmy, jak tragicznie wygląda funkcja processDirection i jak potwornie się z niej korzysta. Enum nam tutaj zapewnia czytelność.

Pamiętajmy też, że możemy podać tylko wartość pierwszego argumentu (np. ustawić, że będzie 1), następne będą o 1 większe. Możemy też jakiś typ tekstowy przypisać, też obleci:

enum CountActionKind {
    INCREASE = 'INCREASE',
    DECREASE = 'DECREASE',
    CLEAR = 'CLEAR'
  }

Ale nie mieszajmy typów. W ogóle najlepiej trzymać się liczb, jest też dyskusja w świecie TSa, czy enumów w ogóle powinno się używać.

Podam jeszcze jedną ciekawą rzecz:

const enum EDirection {
    Up,
    Down,
    Left,
    Right,
  }
   
  const ODirection = {
    Up: 0,
    Down: 1,
    Left: 2,
    Right: 3,
  } as const;


  EDirection.Up;

  ODirection.Up;

Tak się bawić też możemy. Cóż, jak zobaczymy enuma w następnych lekcjach, to już wiemy o co chodzi. Więcej TSa niedługo!