Enums in JavaScript

Posted

Enums in JavaScript

Enumaral type is a very handy concept that assures your variable cannot be any other value except one that was defined. In short:

Variables with a fixed number of values

Enumerals do not exist in JavaScript, however, it doesn't mean it cannot be implemented with some workarounds.

Workarounds

Object

with frozen values

const seasons = Object.freeze({
    AUTUMN: 'autumn',
    SPRING: 'spring',
    SUMMER: 'summer',
    WINTER: 'winter',
});

const season = seasons.spring;

Declared type

as annotation

/**
 * @type {season}
 */
const season = 'summer';

/**
 * @typedef {'autumn' | 'spring' | 'summer' | 'winter'} season
 **/

Exportable constants

as single-file entity

export const AUTUMN = 'autumn';
export const SPRING = 'spring';
export const SUMMER = 'summer';
export const WINTER = 'winter';

As you might know we at Zattoo using TypeScript with JSDoc to benefit from writing vanilla JavaScript code fully covered by standalone TypeScript validation.

We tried all of these approaches described above + checked TS Enums and stopped on exportable constants because they are:

  • tree-shakable unlike object
  • usages trackable unlike defined type
  • have no integration issues with JS unlike TS Enums

How does it work?

Values defined in a single file as exportable constants

export const AUTUMN = 'autumn';
export const SPRING = 'spring';
export const SUMMER = 'summer';
export const WINTER = 'winter';

Type Definitions imported in total and assigned to exportable type

import * as seasons from './seasons';

export type season = typeof seasons[keyof typeof seasons];

Both values and type can be used safely inside some logic

import * as seasons from './seasons';

/**
 * @param {number} month
 * @returns {season}
 **/
const getSummer = (month) => {
    if ([5, 6, 7].includes(month)) {
        return seasons.SUMMER;
    }

    return null;
}

/**
 * @typedef {import('./interfaces').season} season
 */

It might look like a lot of hassle at first glance to write that much code for one enum, but once enum is spread into all the corners of a mid-large size codebase you can quickly understand the benefit from better control and overview of usages.