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!