Skip to content

schnej7/better-enum

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

25 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

BetterEnum

BetterEnum is a lightweight TypeScript utility class for defining extensible, object-oriented enums with behavior. It enables enum-like static fields that retain their identity, support reverse lookups by name, and allow for rich custom behavior through class instances.

✨ Features

  • Enum-like static fields with rich instance behavior
  • Reverse lookup from string name (fromString)
  • Forward serialization to string (toString)
  • Enumeration of defined values (values)
  • Fully type-safe and extensible

πŸš€ Installation

npm install better-enum

Or with Yarn:

yarn add better-enum

🧠 Why?

JavaScript/TypeScript enums are limited: they can't hold methods, complex data, or behavior. BetterEnum allows you to define classes with static members that behave like enums and objects β€” think Java-style enums with methods and fields.


πŸ“¦ Usage

Define a Custom Enum

import BetterEnum, { RegisterEnum } from 'better-enum';

@RegisterEnum
class Status extends BetterEnum {
  static LOADING = new Status(true);
  static READY = new Status(false);

  private isBlocked: boolean;

  constructor(isBlocked: boolean) {
    super();
    this.isBlocked = isBlocked;
  }

  getIsBlocked() {
    return this.isBlocked;
  }
}

Access Enum Values

Status.LOADING.getIsBlocked(); // true
Status.READY.getIsBlocked();   // false

Get All Values

Status.values(); // [Status.LOADING, Status.READY]

Convert to and from Strings

Status.LOADING.toString(); // "LOADING"
Status.fromString("READY") === Status.READY; // true

πŸŽ“ Advanced Example

@RegisterEnum
class RCMascot extends BetterEnum {
  public static readonly SNAP = Object.freeze(new RCMascot({
    name: 'Snap',
    doMath: (a, b) => a + b,
  }));

  public static readonly CRACKLE = Object.freeze(new RCMascot({
    name: 'Crackle',
    doMath: (a, b) => a - b,
  }));

  public static readonly POP = Object.freeze(new RCMascot({
    name: 'Pop',
    doMath: (a, b) => a * b,
  }));

  private name: string;
  private doMathImpl: (a: number, b: number) => number;

  constructor(args: { name: string, doMath: (a: number, b: number) => number }) {
    super();
    this.name = args.name;
    this.doMathImpl = args.doMath;
  }

  getName() {
    return this.name;
  }

  doMath(a: number, b: number) {
    return this.doMathImpl(a, b);
  }
}
RCMascot.SNAP.getName(); // "Snap"
RCMascot.POP.doMath(2, 3); // 6
RCMascot.fromString("CRACKLE") === RCMascot.CRACKLE; // true
RCMascot.values(); // [SNAP, CRACKLE, POP]

πŸ“˜ API

class BetterEnum

Base class to extend when creating enum-like classes.


static values(): T[]

Returns all enum values defined as static members on the subclass.


static fromString(key: string): T | undefined

Returns the instance matching the given string name. Returns undefined if not found.


toString(): string

Returns the string name of the enum instance based on its static member name.


πŸ§ͺ Tests

The package includes thorough test coverage using Node's native test module and assert.

Run tests:

node --test

βš™οΈ Configuration

To use the @RegisterEnum decorator, ensure your tsconfig.json includes:

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  }
}

⚠️ Caveats

  • Classes extending BetterEnum must use the @RegisterEnum decorator for automatic registration.
  • Static fields must be declared before runtime use for registration to succeed.
  • The @RegisterEnum decorator requires TypeScript with experimentalDecorators: true in your tsconfig.json.

πŸ™Œ Acknowledgments

Inspired by Java-style enums with an ergonomic TypeScript twist.

About

Better Enum for TypeScript/Javascript

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors