Skip to content

eye-wave/better-enums

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

vite-plugin-better-enums

TypeScript enums are famously problematic - they compile to IIFEs, they block tree-shaking.

This plugin rewrites export enum declarations at build time into plain named const exports in a virtual module, giving you all the ergonomics of enums with none of the baggage.

// ------------
// Before
// ------------

//#region src/enum.ts
var Fruit = /* @__PURE__ */ (function (Fruit) {
  Fruit[(Fruit["Apple"] = 0)] = "Apple";
  Fruit[(Fruit["Banana"] = 1)] = "Banana";
  Fruit[(Fruit["Kiwi"] = 2)] = "Kiwi";
  return Fruit;
})({});
//#endregion

//#region src/main.ts
var a = Fruit.Apple;
console.log(a);
console.log(Fruit.Banana);
//#endregion

// ------------
// After
// ------------
var a = 1;
console.log(a);
console.log(2);

Usage stays exactly the same (except the indexing starts from 1 not 0):

import { Fruit } from "./fruit";

const pick: Fruit = Fruit.Apple; // 1

How it works?

// ------------
// input
// ------------
export enum Fruit {
  Apple,
  Banana,
  Kiwi,
}

// ------------
// output generated by the plugin
// ------------
export * as Fruit from "\0enum:/abs/path/fruit.ts?Fruit";
export type Fruit = 1 | 2 | 3;

// ------------
// generated Virtual Module
// ------------
export const Apple = 1;
export const Banana = 2;
export const Kiwi = 3;

Why

TypeScript enum This plugin
Tree-shakeable
Works with isolatedModules
Serializes cleanly to JSON
Familiar import syntax
Type-safe

Installation

npm install -D git+https://github.com/eye-wave/better-enums.git

Setup

// vite.config.ts
import { defineConfig } from "vite";
import betterEnums from "vite-plugin-better-enums";

export default defineConfig({
  plugins: [betterEnums()],
});

The plugin runs with enforce: "pre" so it transforms your source before esbuild or any other plugin sees it.


Usage

Write enums exactly as you normally would - just make sure they're exported:

// status.ts
export enum Status {
  Pending,
  Active,
  Archived,
}

Import and use them identically to before:

import { Status } from "./status";

function canEdit(s: Status): boolean {
  return s === Status.Active;
}

Multiple enums in one file work fine:

export enum Color {
  Red,
  Green,
  Blue,
}
export enum Size {
  Small,
  Medium,
  Large,
}

Non-exported enums are left completely untouched.


Values

Members are assigned sequential integers in declaration order:

export enum Direction {
  North, // 1
  East, // 2
  South, // 3
  West, // 4
}

Note: Initializers (Foo = 5) are unsupported right now and will throw a build error pointing to the offending member.


Limitations & Caveats

Since this plugin transforms enums into plain objects at build time, there are a few architectural differences from standard TypeScript enums:

  • No Reverse Lookups: You cannot do Fruit[1] to get the string "Apple". Only forward lookups (Fruit.Apple) are supported.
  • Custom Initializers Unsupported: Explicit values (like Enum = 5 or Enum = "value") are currently unsupported and will throw a build error. All enums are strictly auto-incremented starting from 1.
  • Ambient Enums: declare enum statements are ignored.

License

MIT

About

vite plugin that rewrites ts enums into tree-shakeable named const exports

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors