A TypeScript library for enums, inspired by Java enums and forked from Enumify.
Dr. Axel Rauschmeyer created Enumify to bring an analogue of Java's Enums to JavaScript. In a blog post, he explained why a naive implementation of enums in JavaScript lacks the power of Java Enums.
TypeScript Enums provide a start to a Java-style Enum implementation, but they lack the killer feature of Java's Enum: classes. Java's Enums are full classes, enabling properties and methods (including abstract methods and overriding within an enum). In contrast, TypeScript enums are limited to being namespaced integers or strings.
Enumify is a strong introduction to class-style enums in JavaScript, and this project ports the idea to TypeScript. This port loses the feature from Enumify of creating an enumeration from an array of Strings, but string-based TypeScript enums were added in 2.4.1, so that is not a large loss.
Install:
npm install ts-enums
Use:
import {Enum, EnumValue} from 'ts-enums';
export class Color extends EnumValue {
constructor(name: string) {
super(name);
}
}
class ColorEnumType extends Enum<Color> {
RED: Color = new Color('RED name');
GREEN: Color = new Color('GREEN name');
BLUE: Color = new Color('BLUE 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
new Color();
// Error: EnumValue classes can’t be instantiated individually
Unfortunately, this is not as terse as Enumify's syntax. Here are the steps:
- We define the implementation of EnumValue that defines each of the instances.
- We implement each instance of the EnumValue as a property on the Enum. Within the Enum, we call
initEnum()
with a unique name to set up all of the Enum-specific behavior. - We export an instance of the enum so that other modules can use it.
Enum exposes the getter values
, which produces an Array with all enum values:
for (const c of ColorEnum.values) {
console.log(c.toString());
}
// 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
true
Ts-Enums adds two properties to every enum value:
-
propName
: the property name of the object in the Enum.> ColorEnum.BLUE.name 'BLUE'
-
ordinal
: the position of the enum value within the Arrayvalues
.> ColorEnum.BLUE.ordinal 2
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
* The directory [test/](test) contains examples.
* See [ngrx-example-app-enums](https://github.com/LMFinney/ngrx-example-app-enums) for a more complicated implementation supporting an [@ngrx](https://github.com/ngrx/store) app.