Привет Всем.
Меня зовут Михаил. В НЛМК нахожусь на должности Frontend-разработчика. Занимаюсь разработкой внутренних информационных систем на React + Typescript.
В этой статье поговорим про тип enum (перечисление) в Typescript, о случаях когда его можно и нужно использовать, а когда нет.
Перечисления бывают числовыми и строковыми. Например, представим в виде перечисления должности работников кафе.
Рассмотрим перечисления с числовыми значениями:
Каждому элементу перечисления соответствует числовая константа начиная с 0 и увеличивается на 1 при движении сверху вниз по перечислению.
В этом легко убедиться:
в консоле мы увидим следующее:
Можно менять порядок, если проинициализировать один из элементов числовым значением.
Тогда элементы после будут увеличены на 1 от заданного значения:
Рассмотрим перечисления со строковыми значениями:
в консоли мы увидим:
Числовые и строковые перечисления можно смешивать.
TypeScript компилируется в JavaScript. При компиляции типы удаляются и остается чистый JavaScript код. Например, простая функция суммирования с определением типов
превратится в:
Как мы видим, компилятор удалил все объявления типов.
Но с enum это работает немного иначе.
Разберем для чего и когда можно использовать enum, а когда лучше обойтись простым константным объектом.
Основной аргумент против enum - при компиляции enum, компилятор создает дополнительный JavaScript код и усложняет работу компилятору.
Вернемся к примеру с перечислением должностей работников кафе.
Используем enum и посмотрим на результат компиляции:
превратилось в:
Получили не очень приятную конструкцию, состоящую из переменной и анонимного самовызывающегося функционального выражения.
При этом можно использовать методы объекта, например:
В консоли мы увидим:
Попробуем заменить enum на константный объект и посмотрим результаты компиляции:
превратится в:
Тут константный объект определенно хорош.
Но enum может еще лучше!
Для этого используем ключевое слово const:
Взглянем на результат компиляции:
Теперь нет объекта, нет лишней переменной и анонимного самовызывающегося функционального выражения.
Получается, enum использовать даже профитнее, чем объект?
В этой части да, но есть несколько нюансов:
-
Если в вашем проекте в файле tsconfig.json в секции compilerOptions свойство preserveConstEnums выставлено со значением true, то эффекта от использования const enum не будет.
Проверим это на нашем примере.
Поставим флаг в true:
И посмотрим на результат компиляции:
превратился в:
Т.е. весь эффект от использования const enum потерян и не имеет смысла.
Если вам необходим только доступ к значению, то однозначно используйте enum.
А вот если вам нужно где-то перебрать или получить все значения или ключи, то используйте константный объект а не const enum.
Почему не const enum, смотрим:
Мы увидим ошибку:
А все потому, что нашего const enum не окажется в скомпилированном коде.
Когда необходимо получить все значения или ключи, константный объект в скомпилированном коде сильно выигрывает у enum без использования const.
О типизации
Типизируем параметр принимаемый функцией “printPosition”:
или так:
Но руками создавать union тип - это не то, что хотелось бы делать.
При использовании enum:
если нам где-то понадобится типизировать принимаемый параметр по ключам enum.
если нам где-то понадобится типизировать принимаемый параметр по значениям enum:
достаточно использовать шаблонную строку. Главное не забывать использовать const.
Итак, подытожим плюсы и минусы использования enum:
Минусы:
При использовании enum без const компилятор создает дополнительный JavaScript код, что усложняет работу компилятору и размер финального бандла;
При использовании enum с const - нет возможности получить для обработки все ключи или значения enum.
Необходимо следить за флагом свойства preserveConstEnums в файле tsconfig.json в секции compilerOptions, чтобы получить профит.
Плюсы:
При использовании const enum и необходимости только в значении дает отсутствие избыточного кода в скомпилированном JavaScript, а значит, меньший размер и лучшую производительность;
При использовании const enum - возможность быстрой и удобной типизации в отличие от использования константных объектов;
Использование enum упрощает рефакторинг кода, изменение значения enum автоматически обновляет все его использования в проекте. Это помогает избежать ошибок, связанных с поиском и заменой значений вручную.
Обнаружение ошибок на этапе компиляции: TypeScript выдаст ошибку на этапе компиляции, если использовать значение, которое не входит в enum. Это помогает избежать ошибок при использовании неверных значений.
Автодополнение в редакторах кода: Редакторы кода предлагают автодополнение для значений enum, что ускоряет процесс написания кода, уменьшает вероятность опечаток и ошибок.
Самодокументируемый код: Определение enum с именованными значениями добавляет дополнительную информацию о том, какие значения ожидаются и задумывались разработчиком. Это делает код более самодокументируемым и легче понимаемым для других разработчиков.
Итого:
На мой взгляд, понимание плюсов и минусов использования enum при разработке несомненно даст исключительно положительный эффект, как минимум, это уменьшение размера бандла и легкая типизация.
Спасибо за внимание! Пишите комментарии, буду рад узнать ваше мнение по данному вопросу!
Комментарии (2)
Onni
28.12.2023 08:49Я использовал enum в CocosCreator так:
enum UnitId { } enum ItemId { } var units: Recor<UnitId, Unit>; function spendItem(unitId: UnitId, itemId: ItemId, amount: Int) { ... }
Вместо того что бы использовать простой number. Так компилятор не давал перепутать id-ки и и выполнить: `const unit = units[itemId]`
Правда не нашел какими флагами это включается на TSPlayground
Andchir
На практике получалось ли получить ощутимую разницу? У вас сотни енамов коде одного проекта?
На сколько эта разница в производительности существенна не хотите проверить?
Логично. Именно поэтому и существуют эти два типа данных в языке.