
After enough frontend work, the “should we use TypeScript enums?” debate matters less than a more...
After enough frontend work, the “should we use TypeScript enums?” debate matters less than a more practical problem.
The enum itself is rarely the painful part.
The painful part is keeping labels, colors, options, filters, and validation logic in sync.
A status code starts as a simple backend value:
0 = draft1 = published2 = archivedThen the UI needs more:
And suddenly one tiny enum becomes three, four, or five runtime structures spread across your codebase.
That’s the problem this post is really about.
as const objects are both useful.enum-plus is most interesting when enum-like values need to drive labels, metadata, i18n, and UI lists from one definition.A typical codebase ends up with something like this:
export enum ArticleStatus {
Draft = 0,
Published = 1,
Archived = 2,
}
export const articleStatusLabels: Record<ArticleStatus, string> = {
[ArticleStatus.Draft]: 'Draft',
[ArticleStatus.Published]: 'Published',
[ArticleStatus.Archived]: 'Archived',
};
export const articleStatusColors: Record<ArticleStatus, string> = {
[ArticleStatus.Draft]: 'gray',
[ArticleStatus.Published]: 'green',
[ArticleStatus.Archived]: 'red',
};
export const articleStatusOptions = [
{ value: ArticleStatus.Draft, label: articleStatusLabels[ArticleStatus.Draft] },
{ value: ArticleStatus.Published, label: articleStatusLabels[ArticleStatus.Published] },
{ value: ArticleStatus.Archived, label: articleStatusLabels[ArticleStatus.Archived] },
];
None of this code is wrong.
The problem is that one business concept now lives in multiple runtime structures, and they drift unless someone keeps them aligned.
as const solves one problem — not all of themA plain as const object is still my default when I only need constants and a union type:
const ArticleStatus = {
Draft: 0,
Published: 1,
Archived: 2,
} as const;
type ArticleStatus = typeof ArticleStatus[keyof typeof ArticleStatus];
That works well for type-level constraints.
It stops being enough when the same values also need labels, i18n, colors, option lists, reverse lookups, or extra metadata at runtime.
enum-plus is actually good atenum-plus is easy to describe as “a drop-in replacement for native enum”, but I think that undersells the most useful part.
enum-plus seems most useful when you want one runtime definition to drive both typed values and UI-facing data such as labels, metadata, and option lists.
That means your enum can power:
And it does this in a package that is:
Here’s a practical example:
import { Enum } from 'enum-plus';
const ArticleStatus = Enum({
Draft: {
value: 0,
label: 'Draft',
color: 'gray',
icon: 'edit',
},
Published: {
value: 1,
label: 'Published',
color: 'green',
icon: 'check-circle',
},
Archived: {
value: 2,
label: 'Archived',
color: 'red',
icon: 'archive',
},
});
Now one definition can drive multiple use cases:
ArticleStatus.Published; // 1
ArticleStatus.label(1); // 'Published'
ArticleStatus.key(1); // 'Published'
ArticleStatus.items; // UI-friendly iterable items
ArticleStatus.findBy('color', 'red') // enum item lookup
ArticleStatus.named.Published.raw; // { value: 1, label: 'Published', color: 'green', icon: 'check-circle' }
And if you want direct access to one metadata field:
ArticleStatus.named.Published.raw.color; // 'green'
That may not look dramatic at first glance, but it removes a lot of scattered glue code.
Suppose your backend returns article rows with a numeric status field.
Your UI might need to:
With the usual approach, these concerns get split across separate maps and helpers.
With a runtime enum definition, they can come from one place.
That doesn’t just save lines of code.
It reduces the number of places where your business vocabulary can silently diverge.
as const vs enum-plusHere’s the practical tradeoff table I wish more articles included:
| Approach | Good for constants/types | Labels and metadata in the same definition | Can generate UI lists from the same definition | Extra maps/helpers needed |
|---|---|---|---|---|
native enum | yes | no | no | yes |
as const object | yes | not by itself | not by itself | yes |
enum-plus | yes | yes | yes | fewer |
So no, enum-plus is not the right answer for every project.
But it is a strong answer for projects where enum-like values need to drive UI and business display behavior.
A lot of enum discussions in TypeScript are framed around language purity:
as const objects instead?Those are valid questions.
But in app development, the bigger problem is often operational duplication rather than syntax.
If a single backend code needs to become:
then the real design question becomes:
Where does that information live?
That’s the question enum-plus answers better than native enums do.
enum-plusThis part matters.
I would not use enum-plus if:
In those cases, as const may be all you need.
But if your codebase keeps rebuilding the same label maps, option arrays, and metadata dictionaries around status-like values, then it’s worth a serious look.
A few things make the repo more credible than a random experiment:
That combination matters more to me than hype.
I don’t think the strongest pitch for enum-plus is:
“TypeScript enums, but better.”
I think the stronger pitch is:
“A single runtime source of truth for values your UI needs to display, translate, color, filter, and select.”
I wouldn’t use this everywhere.
But if your frontend repeatedly turns one enum into labels, colors, options, filters, and lookup helpers, then a runtime enum definition can be a reasonable abstraction.
aiMost of us have seen a coding agent fail to complete a task we know it can do. We just don't...
googlecloudWhen building Generative AI applications, developers often encounter a massive bottleneck: sequential...
discussI’ve been thinking about sharing some electronic circuit posts on Dev.to — small circuits, DIY...
agentsWhat nobody tells you about exporting your multi-agent prototype to a local workspace. Every...
agenticarchitectAutonomous agents are genuinely good at answering messy business questions. Give one an LLM and a set...
aiPR volume went up, ticket quality didn't, and the gap got filled with LLMs on both sides of the review: bots reviewing, bots replying, bots occasionally arguing with bots about priorities that only existed in a teammate's head. Our CEO named the actual problem, and it's bigger than code review.
Workflows from the Neura Market marketplace related to this Stable Diffusion resource