One object, not four artifacts
The union, the labels map, the options array, the validator — folded into a single definition that can't drift out of sync.
Why it matters
A constant is rarely just a string — it usually has a human label, a stored value, an order, often a little metadata. Smart enums keep all of it on one typed object, intact from the database to the dropdown.
You add one value to a fixed set — a new plan, a new role, a new category. Now the database migration, the labels map, the dropdown options, the validator, and a couple of if statements all have to know about it. None of them were ever connected, so it's on you to remember each one, and the day you miss one the bug ships. That's not carelessness — the language handed you a bare string, so the concept scattered.
Defining one of those values the usual way already costs a line or three — and you still build the label, the options list, and the validator by hand, separately. A smart enum's entire definition is three lines plus a one-line type alias, and the label, lookup, options, and valid-set all come with it:
import { enumeration, type Enumeration } from '@reharik/smart-enum';
const Priority = enumeration('Priority', {
input: ['low', 'medium', 'high'] as const,
});
type Priority = Enumeration<typeof Priority>;And that one definition is the label, the lookup, the options, and the valid-set — here's everything it hands you:
Priority.high; // { key: 'high', value: 'HIGH', display: 'High', index: 2 }
Priority.high.display; // 'High' — the label, no separate map
Priority.fromValue('HIGH'); // Priority.high — runtime lookup, type-narrowed
Priority.items(); // [low, medium, high] — your dropdown options, in order
Priority.values(); // ['LOW','MEDIUM','HIGH'] — your validator setOne short definition in; the whole concept out. Read the full idea →