Skip to content

Instantly share code, notes, and snippets.

@samuelgoto
Last active October 25, 2017 00:05
Show Gist options
  • Save samuelgoto/405251eb4fd7b42d764589418ea2afc4 to your computer and use it in GitHub Desktop.
Save samuelgoto/405251eb4fd7b42d764589418ea2afc4 to your computer and use it in GitHub Desktop.

This is a very early stage 0 exploration to add enums to Javascript, as a syntatic simplication over a common pattern to define enumerations.

Introduction

Enums come up often in code bases (TODO: try to estimate a number) and it is easy to get it incorrectly. Specifically, it is easy to forget:

  • to Object.freeze the object
  • to declare it as a const which avoids having the symbol redefined

With this in mind, we propose a nem keyword to javascript, say enum which de-sugars to the following:

// if you write this ...
enum Foo {
  BAR: 1,
  HELLO "hello",
  WORLD: false
}

// ... it gets de-sugared to:
const Foo = Objec.freeze({
  BAR: 1,
  HELLO: "hello",
  WORLD: false
});

// TODO(goto): should we use Symbols here for extra type safety?
@samuelgoto
Copy link
Author

Python

from enum import Enum
class Color(Enum):
  RED = 1
  GREEN = 2
  BLUE = 3

Makes these things accessible:

>>> print(Color.RED)
Color.RED
>>> type(Color.RED)
<enum 'Color'>
>>> isinstance(Color.GREEN, Color)
True
>>>
>>> print(Color.RED.name)
RED

Support iteration, in declaration order:

>>> for shake in Shake:
...     print(shake)
...
Shake.VANILLA
Shake.CHOCOLATE
Shake.COOKIES
Shake.MINT

@unique enforces the values to be unique:

>>> from enum import Enum, unique
>>> @unique
... class Mistake(Enum):
...     ONE = 1
...     TWO = 2
...     THREE = 3
...     FOUR = 3
...
Traceback (most recent call last):
...
ValueError: duplicate values found in <enum 'Mistake'>: FOUR -> THREE

You can assign auto() values:

>>> from enum import Enum, auto
>>> class Color(Enum):
...     RED = auto()
...     BLUE = auto()
...     GREEN = auto()

You can compare them:

>>> Color.RED is Color.RED
True
>>> Color.RED is Color.BLUE
False
>>> Color.RED is not Color.BLUE
True

Comparisons against non-enumeration values will always compare not equal (again, IntEnum was explicitly designed to behave differently, see below):

>>> Color.BLUE == 2
False

The first variation of Enum that is provided is also a subclass of int. Members of an IntEnum can be compared to integers; by extension, integer enumerations of different types can also be compared to each other:

@samuelgoto
Copy link
Author

Java

An enum type is a special data type that enables for a variable to be a set of predefined constants.
Because they are constants, the names of an enum type's fields are in uppercase letters.

You should use enum types any time you need to represent a fixed set of constants. That includes natural enum types such as the planets in our solar system and data sets where you know all possible values at compile time—for example, the choices on a menu, command line flags, and so on.

public enum Day {
    SUNDAY, MONDAY, TUESDAY, WEDNESDAY,
    THURSDAY, FRIDAY, SATURDAY 
}

The compiler automatically adds some special methods when it creates an enum. For example, they have a static values method that returns an array containing all of the values of the enum in the order they are declared.

You can iterate over them:

for (Planet p : Planet.values()) {
    System.out.printf("Your weight on %s is %f%n",
                      p, p.surfaceWeight(mass));
}

@samuelgoto
Copy link
Author

samuelgoto commented Oct 24, 2017

Examples

https://github.com/jspears/subschema/blob/master/src/listenUtil.js#L144

/**
 * The possible types of listeners that can be added.
 * @readonly
 * @enum {string}
 */
export const MapTypes = {
    'value': 'addListener',
    'error': 'addErrorListener',
    'submit': 'addSubmitListener',
    'state': 'addStateListener',
    'validate': 'addValidateListener',
    'addListener': 'addListener',
    'addErrorListener': 'addErrorListener',
    'addSubmitListener': 'addSubmitListener',
    'addStateListener': 'addStateListener',
    'addValidateListener': 'addValidateListener'
}

https://github.com/WaffleBoardWizard/guild-ball-simulator/blob/04ae96c7561e7b9c3c0959134a34f6a6c3708a58/gb-simulator-web/src/components/Controls/GameBoard/Inputs.js#L1

import Enum from "es6-enum"

export default Enum(
  "PIECE_CLICK",
  "PIECE_DRAG",
  "CLICK_MENU_BUTTON");

https://github.com/Piicksarn/cdnjs/blob/master/ajax/libs/Shuffle/2.0.6/jquery.shuffle.js#L103

jquery

/**
 * Events the container element emits with the .shuffle namespace.
 * For example, "done.shuffle".
 * @enum {string}
 */
Shuffle.EventType = {
  LOADING: 'loading',
  DONE: 'done',
  SHRINK: 'shrink',
  SHRUNK: 'shrunk',
  FILTER: 'filter',
  FILTERED: 'filtered',
  SORTED: 'sorted',
  LAYOUT: 'layout',
  REMOVED: 'removed'
};

angular

https://github.com/angular/bower-material/blob/master/modules/js/panel/panel.js#L2504

/**
 * Possible default closeReasons for the close function.
 * @enum {string}
 */
MdPanelRef.closeReasons = {
  CLICK_OUTSIDE: 'clickOutsideToClose',
  ESCAPE: 'escapeToClose',
};

https://github.com/mirror/chromium/blob/master/chrome/browser/resources/settings/site_settings/constants.js

/**
 * All possible contentSettingsTypes that we currently support configuring in
 * the UI. Both top-level categories and content settings that represent
 * individual permissions under Site Details should appear here.
 * This should be kept in sync with the |kContentSettingsTypeGroupNames| array
 * in chrome/browser/ui/webui/site_settings_helper.cc
 * @enum {string}
 */
settings.ContentSettingsTypes = {
  COOKIES: 'cookies',
  IMAGES: 'images',
  JAVASCRIPT: 'javascript',
  SOUND: 'sound',
  PLUGINS: 'plugins',  // AKA Flash.
  POPUPS: 'popups',
  GEOLOCATION: 'location',
  NOTIFICATIONS: 'notifications',
  MIC: 'media-stream-mic',  // AKA Microphone.
  CAMERA: 'media-stream-camera',
  PROTOCOL_HANDLERS: 'register-protocol-handler',
  UNSANDBOXED_PLUGINS: 'ppapi-broker',
  AUTOMATIC_DOWNLOADS: 'multiple-automatic-downloads',
  BACKGROUND_SYNC: 'background-sync',
  MIDI_DEVICES: 'midi-sysex',
  USB_DEVICES: 'usb-chooser-data',
  ZOOM_LEVELS: 'zoom-levels',
  PROTECTED_CONTENT: 'protectedContent',
  ADS: 'ads',
};

Azure

https://github.com/Azure/azure-storage-node/blob/master/lib/common/util/constants.js

/**
  * Defines the service types indicators.
  * 
  * @const
  * @enum {string}
  */
  ServiceType: {
    Blob: 'blob',
    Queue: 'queue',
    Table: 'table',
    File: 'file'
  },

  /**
  * Specifies the location used to indicate which location the operation can be performed against.
  *
  * @const
  * @enum {int}
  */
  RequestLocationMode: {
    PRIMARY_ONLY: 0,
    SECONDARY_ONLY: 1,
    PRIMARY_OR_SECONDARY: 2
  },

  /**
  * Represents a storage service location.
  *
  * @const
  * @enum {int}
  */
  StorageLocation: {
    PRIMARY: 0,
    SECONDARY: 1
  },

@samuelgoto
Copy link
Author

BigQuery

SELECT
  sample_path,
  sample_repo_name,
  content
FROM [bigquery-public-data:github_repos.sample_contents]
WHERE
  sample_path LIKE '%.js' and
  content LIKE '%@enum%' and
  not content LIKE '%goog%'
  
limit 100;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment