Почему я всегда использую enum в JavaScript

Дата публикации: 2024-05-23

Эта заметка появилась под впечатлением от статьи «Why I don't use enums in TypeScript, and neither should you», которая сейчас удалена. Её автор предлагал вместо enum использовать в TypeScript объекты.

То есть вместо:

enum Colors {
  BLUE = 'blue',
  GREEN = 'green',
  RED = 'red',
}
function printColor(color: Colors) { console.log(color); }
printColor(Colors.BLUE);
printColor('blue');

предлагалось писать:

const Colors = {
  BLUE: 'blue',
  GREEN: 'green',
  RED: 'red',
} as const;
type Colors = typeof Colors[keyof typeof Colors];
function printColor(color: Colors) { console.log(color); }
printColor(Colors.BLUE);
printColor('blue');

Преимуществом называли возможность писать литерал 'blue', не импортируя модуль с перечислением.

В статье «Какова конечная цель программирования?» я рассматриваю иерархию целей разработки, похожую на пирамиду Маслоу.

Подход со строковыми литералами относится к первому уровню — удобству написания кода. Но он не достигает высшего уровня, который я называю изменяемостью.

Действительно, литерал писать проще:

invoice.setState('pending');
order.setState('pending');

Но при поиске всех состояний pending для заказов они смешаются с такими же состояниями счетов. Именно от этого защищают кажущиеся неудобствами импорт и отказ от литералов.

В моём JS-коде я использую пространства имён, унаследованные от Zend1:

const TeqFw_Core_Shared_Enum_Sphere = {
  BACK: 'BACK',
  FRONT: 'FRONT',
  SHARED: 'SHARED',
};
Object.freeze(TeqFw_Core_Shared_Enum_Sphere);
export default TeqFw_Core_Shared_Enum_Sphere;

При использовании подключаю перечисление через внедрение зависимостей и JSDoc:

export default function ({ TeqFw_Core_Shared_Enum_Sphere$: SPHERE }) {
  if (one.sphere === SPHERE.FRONT || one.sphere === SPHERE.SHARED) {
    // ...
  }
}

Так обычным текстовым поиском находятся все места использования TeqFw_Core_Shared_Enum_Sphere. JSDoc помогает IDE перейти к каждому значению — BACK, FRONT или SHARED.

JavaScript, в отличие от TypeScript, не запрещает передать литерал напрямую. Но ответственность разработчика — использовать возможности инструментов во благо, а не во вред. Да, enum в JavaScript фактически не реализован, хотя слово зарезервировано. Но я считаю полезным писать код так, как будто он есть.

Дополнительные фрагменты исходного кода

const TeqFw _Core_Shared_Enum_Sphere = {
};
Object.freeze(TeqFw _Core_Shared_Enum_Sphere);
export default TeqFw _Core_Shared_Enum_Sphere;
export default function (
{
}
) {
if (
) {
}
} With this approach, you can find all the places where TeqFw_Core_Shared_Enum_Sphere is used through simple text search. Using JSDoc annotations helps the IDE (PhpStorm) navigate through the code and find usages of each individual value (BACK, FRONT, SHARED) within the IDE.
if (
) {
}