0.1.0 • Published 8 years ago

enummer v0.1.0

Weekly downloads
-
License
ISC
Repository
-
Last release
8 years ago

enummer NPM version

A 'real' Enum implementation for JavaScript with typesafety, ordinal support and comparison support. inspired by Java. Typed with Flow and supports ES-modules.

Installation

Simply do: npm install enummer.

What is it?

A proper Enum implementation for Javascript. Unlike other Enum implementations, this one follows the Java implementation very strongly and supports:

  • Ranked Enum constants (ordinals)
  • Support for instanceof and isPrototypeof checks.
  • Support for native comparisons with the <, > and === operatiors.
  • Typesafety. Built with flow and throws runtime exceptions.
  • Immutability. All Enum constants are immutable and accesses happens through getters.

Example 1

import Enum from "enummer";

const Day = Enum.define("Day",
	"MONDAY", "TUESDAY", "WEDNESDAY"
);

Day.toString()                   // Day { MONDAY, TUESDAY, WEDNESDAY }
Day.MONDAY instanceof Day        // true
Day.MONDAY < Day.TUESDAY         // true
Day.WEDNESDAY === Day.WEDNESDAY  // true
Day.values()                     // [ MONDAY {}, TUESDAY {}, WEDNESDAY {} ]
Day.MONDAY.getDeclaringClass()   // Day { MONDAY, TUESDAY, WEDNESDAY }
Enum.isPrototypeOf(Day)          // true

Example 2 - with explicit ordinals

import Enum from "enummer";

const FavoriteColor = Enum.define("FavoriteColor",
	"BLUE(2)", "RED(1)", "YELLOW(10)"
);

FavoriteColor.toString()               // FavoriteColor { MONDAY, TUESDAY, WEDNESDAY }
FavoriteColor.BLUE > FavoriteColor.RED // true, Blue has higher ordinal than red.

Example 3 - as an object with explicit ordinals

import Enum from "enummer";

const FavoriteColor = Enum.define("FavoriteColor", {
	BLUE:   2,
	RED:    1,
	YELLOW: 10
});

FavoriteColor.toString()               // FavoriteColor { MONDAY, TUESDAY, WEDNESDAY }
FavoriteColor.BLUE > FavoriteColor.RED // true, Blue has higher ordinal than red.

Example 4 - with floating point numbers an 'Infinity'

import Enum from "enummer";

const FavoriteColor = Enum.define("FavoriteColor", {
	BLUE:   2.2,
	RED:    2.1,
	YELLOW: Infinity
});

FavoriteColor.BLUE > FavoriteColor.RED      // true, Blue has higher ordinal than red.
FavoriteColor.YELLOW > FavoriteColor.BLUE   // true, no value would ever be larger than 'YELLOW'.

Changelog:

v0.1.0:

  • Added support for browsers that doesn't support Object.entries() and Object.keys(). Previous versions didn't work in Safari due to missing support for Object.entries().

v0.0.9:

  • Fixed a few typing errors.

v0.0.6:

  • Enummer now supports floating point numbers for ordinals as well as setting Infinity as ordinal value.

v0.0.5:

  • Enummer now supports an alternative syntax for enum constants. They can now be written as objects. For instance:
Enum.define("MyEnum", {TODAY: 1, YESTERDAY: 2})

Is now acceptable. Note that you need to declare ordinals (a number) for each key.

v0.0.4:

  • Previous versions wouldn't work in environments without native class support. This is fixed now. Added a missing semicolon.

v0.0.3:

  • Updated package dependency and keywords.

v0.0.2:

  • First release!

Usage

Import it in your project like this:

import Enum from "enummer"                 // (standard) Transpiled to ES5, inlined dependencies.;
// or

import Enum from "enummer/external"        // Transpiled to ES5, external dependencies.
// or

import Enum from "enummer/native"          // Transpiled to ES5, native ES-modules, inlined dependencies.
// or

import Enum from "enummer/native-external" // Transpiled to ES5, native ES-modules external dependencies.
// or

import Enum from "enummer/typed"           // Flow typings, ES-modules, external dependencies.

Documentation

Construction

The Enum class is abstract and can't be instanced directly. Instead, use the static define method for constructing enums:

const MyEnum = new Enum("MyEnum", "a", "b", "c") // Throws a SyntaxError, Enum is an abstract class.

const MyEnum = Enum.define("MyEnum", "a", "b", "c") // Works!

Ordinals:

The ranking order of your Enum types will by default increase with 1 for each constant. For instance:

const MyEnum = Enum.define("MyEnum", "a", "b", "c");

MyEnum.a.ordinal === 0; //true
MyEnum.b.ordinal === 1; //true
MyEnum.c.ordinal === 2; //true

However, you can change this ordering however you like. Consider the following:

const MyEnum = Enum.define("MyEnum", "a(2)", "b", "c");

MyEnum.a.ordinal === 2; //true
MyEnum.b.ordinal === 3; //true
MyEnum.c.ordinal === 4; //true

Simply attach (n) to each constant where n equals the rank (ordinal). For instance, a(2) gets the ordinal 2. All remaining values will have an increasing order in relation to that.

You can also set the ordering however you like:

const MyEnum = Enum.define("MyEnum", "a(2", "b(5)", "c(10)");

MyEnum.a.ordinal === 2; //true
MyEnum.b.ordinal === 5; //true
MyEnum.c.ordinal === 10; //true

And even:

const MyEnum = Enum.define("MyEnum", "a(2", "b(5)", "c");

MyEnum.a.ordinal === 2; //true
MyEnum.b.ordinal === 5; //true
MyEnum.c.ordinal === 6; //true

Note that you can define your enum constants with objects instead. Using that notation, all enum constants needs to have an associated ordinal:

const MyEnum = Enum.define("MyEnum", {
	MONDAY:     1,
	TUESDAY:    2,
	WEDNESDAY:  3
});

Comparisons

The ordinals allows us to do classic comparisons between Enum constants. For instance, consider the following:

const FavoriteColor = Enum.define("FavoriteColor",
	"BLUE(2)", "RED(1)", "YELLOW(10)"
);

FavoriteColor.BLUE > FavoriteColor.RED    // true, BLUE has higher ordinal than RED.
FavoriteColor.YELLOW > FavoriteColor.BLUE // true, YELLOW has higher ordinal than BLUE.

Two Enum constants cannot have the same ordinal. This is because the ordinal is often stored in a database as representative of the Enum constant. Thus, two enum constants are only equal if there is referential equality:

FavoriteColor.BLUE === FavoriteColor.BLUE // true

Type safety

You can only construct a new Enum Type with strings. This is because the strings will be used as the names of the inner classes.

For instance, this will throw a TypeError:

const MyEnum = Enum.define("MyEnum", 2, 10, 15); // Throws a TypeError
const MyEnum = Enum.define(SomeObject, "a", "b", "c") // Throws a TypeError, first argument must be a string.

instanceof and isPrototypeOf

Because the static define method on the abstract Enum class generates a new Baseclass with subclasses for each given Enum constant, enummer generates 'real' enums that makes it possible to do type assertions. For instance, consider this Flow example:

const Day = Enum.define("Day", "MONDAY", "TUESDAY", "WEDNESDAY");
Day.MONDAY instanceof Day // true.

function iRequireADayEnum (day: Day) {
	if (!(day instanceof Day)) throw new Error();
	console.log("wee!");
}
iRequireADayEnum(Day.MONDAY); // Prints 'wee!' to the console.

Generated Enum types has Enum as their prototype. That means that the following is true:

const MyEnum = Enum.define("MyEnum", "a", "b");
Enum.isPrototypeOf(MyEnum) // true
0.1.0

8 years ago

0.0.9

8 years ago

0.0.8

8 years ago

0.0.7

8 years ago

0.0.6

8 years ago

0.0.5

8 years ago

0.0.4

8 years ago

0.0.3

8 years ago

0.0.2

8 years ago

0.0.1

8 years ago