I’ve been working as a developer primarily in TypeScript for a couple years, and I really love the language. When I transitioned from Java to JavaScript in 2014, I loved the freedom and functional programming that JavaScript provided, but I missed the classes and types from Java. TypeScript has been a great intermediate language for me, giving me access to the web and functional programming, but with an optional structure that feels at home.

One area that was missing for me in TypeScript, though, was Enums. TypeScript has an Enum concept, but it’s nowhere nearly as powerful as Java’s Enums. Whereas TypeScript Enums are essentially namespaced groups of numbers (or strings, as of 2.4), Enums in Java are full classes. Not only can you create Java Enums that simply create a collection of namespaced strings, but you can also implement properties and logic for all of the instances (which I used to full effect in an article I wrote for OCI on extending them).

Fortunately, Dr. Axel Rauschmeyer created Enumify to bring an analogue of Java’s Enums to JavaScript (in a blog post, he expands on why a naive implementation of enums in JavaScript lacks the power of Java Enums).

Enumify is a strong introduction to class-style enums in JavaScript, and I’m happy to announce that I’ve forked Enumify to release ts-enums, a TypeScript-specific extension of Dr. Rauschmeyer’s ideas, with a slightly different API.

An Example

import {Enum, EnumValue} from 'ts-enums'; export class Color extends EnumValue { constructor(name: string) { super(name); } } class ColorEnumType extends Enum { RED: Color = new Color('RED name'); GREEN: Color = new Color('GREEN name'); BLUE: Color = new Color('BLUE name'); BLACK: Color = new Color('BLACK name'); constructor() { super(); this.initEnum('Color'); } } export const ColorEnum: ColorEnumType = new ColorEnumType(); // examples of use console.log(ColorEnum.RED.toString()); // Color.RED console.log(ColorEnum.GREEN instanceof Color); // true

Properties of Enum classes

Enum exposes the getter values , which produces an Array with all enum values:

for (const c of ColorEnum.values) { console.log(c); } // Output: // Color.RED // Color.GREEN // Color.BLUE

Enum exposes the methods byPropName and byDescription , to extract the EnumValue instance by either the property name of the object in the Enum or the description string passed into the EnumValue’s constructor, respectively:

console.log(ColorEnum.byPropName('RED') === ColorEnum.RED); // true console.log(ColorEnum.byDescription('RED name') === ColorEnum.RED); // true

Enums as classes

The EnumValues are full TypeScript classes, enabling you to add properties and methods (see the tests for more examples).

import {Enum, EnumValue} from 'ts-enums'; import {Color, ColorEnum} from 'color'; class BridgeSuit extends EnumValue { constructor(name: string, private _isMajor: boolean = false) { super(name); } // can use simple properties (defensively-copied // to maintain immutability) get isMajor(): boolean{ return this._isMajor; } // can also use methods, though this isn't an ideal implementation. // (I would probably used another property instead of an if-else) get color(): Color { if (this === BridgeSuiteEnum.SPADES || this === BridgeSuiteEnum.CLUBS) { return ColorEnum.BLACK; } else { return ColorEnum.RED; } } } class BridgeSuitEnumType extends Enum { SPADES: BridgeSuit = new BridgeSuit('Spades', true); HEARTS: BridgeSuit = new BridgeSuit('Hearts', true); DIAMONDS: BridgeSuit = new BridgeSuit('Diamonds'); CLUBS: BridgeSuit = new BridgeSuit('Clubs'); constructor() { super(); this.initEnum('BridgeSuit'); } // can also have methods on the overall type get majors(): BridgeSuit[] { return this.values.filter((suit: BridgeSuit ) => suit.isMajor); } } const BridgeSuitEnum: BridgeSuitEnumType = new BridgeSuitEnumType(); console.log(BridgeSuitEnum.HEARTS.color.toString()); // Color.RED console.log(BridgeSuitEnum.HEARTS.isMajor); // true

More information

See ngrx-example-app-enums for a more complicated implementation supporting an @ngrx app.