Member surfaces
Choose between .enum, .values, .rawEnum, .rawValues, and .cases.
An enumwaii declaration exposes several typed views of the same closed set. Each view serves a specific application or integration role.
const = (["ADMIN", "USER"]);
const = .;
const = .;
const = .;
.; // branded application value
.; // branded member tuple
.; // raw literal "ADMIN"
.; // raw literal tuple
.; // raw discriminant "ADMIN".enum: the default
Use .enum for application values, comparisons, defaults, fixtures, function arguments, and derivation.
const = .;
function (: (typeof )["~type"]) {}
(.);
("ADMIN"); // TypeScript error.enum is the standard surface for trusted application code.
For the object overload, property names and canonical values may differ:
import { } from "enumwaii";
const = ({
: "order-paid",
: "order-pending",
});
const = .;
.; // branded "order-paid"
.("order-paid"); // valid
.("ORDER_PAID"); // throwsThe keys are only the developer-facing object surface. .values, .rawValues, parsing, schemas, adapters, and derivation all use the mapped values.
Member-level JSDoc is preserved from object properties to hover information on .enum members. Use a fully documented identity map such as em({ /** ... */ READY: "READY" }) when every member needs documentation. TypeScript does not expose tuple-element comments through mapped property symbols, so comments inside em([/* ... */ "READY"]) cannot appear on enum.READY. The no-object-em rule recognizes a fully documented object as this intentional documentation form.
Extract member views once and reference members through the extracted constant:
const = .;
.; // preferred
..; // lint errorThe same convention applies to .rawEnum and .cases. It makes the owning vocabulary visually stable and prevents instance expressions from leaking throughout application code. Other instance APIs such as roles.parse(...), roles.derive(...), and roles.values remain direct APIs.
.values: branded iteration
Use .values when iterating over owned application members:
for (const of .) {
();
}The tuple carries declaration provenance. Do not pass it back into em() to reconstruct another declaration; use pick, omit, extend, or em.combine to preserve the intended identity relationship.
.rawEnum and .rawValues: integration escapes
Some APIs require literal strings or literal arrays and cannot preserve enumwaii's brand. .rawEnum and .rawValues provide canonical unbranded values without making raw literals the normal authoring style. With an object declaration, .rawEnum retains the supplied developer-facing keys while .rawValues contains only the mapped values.
const = .;
.({ : . });
.("role", .);Keep these surfaces at the integration boundary, then parse values returning from that boundary to establish application ownership.
.cases: native discriminated-union narrowing
TypeScript does not reliably narrow discriminated unions when the discriminant is a branded string intersection. .cases supplies raw literal tags for union definitions, switch, and equality narrowing:
const = (["CREATED", "DELETED"]);
const = .;
type =
| { : typeof .; : <string, unknown> }
| { : typeof .; : string };
function (: ) {
switch (.) {
case .:
.; // correctly narrowed
break;
case .:
.; // correctly narrowed
}
}.cases is not a second general-purpose enum. Treat .enum as the application-value surface and .cases as the narrow compatibility surface for discriminated unions. The .cases object carries a type marker so enumwaii's lint rules can recognize its provenance and keep its members in union definitions and narrowing positions.
Runtime identity and object behavior
.enum, .rawEnum, and .cases are different static views of one canonical frozen object:
.(., .); // true
.(., .); // trueThey are frozen plain objects rather than proxies. Unknown properties therefore return undefined, which lets React, serializers, assertion libraries, inspectors, and promise detection probe them without triggering member-access errors.
The distinction between the surfaces exists entirely in TypeScript. Runtime code cannot recover which view a consumer used.
Type-only properties
Three declaration-local properties provide compile-time utilities. They are not emitted at runtime:
type = (typeof )["~type"];
type = (typeof )["~keys"];
type = (typeof )["~safeParseResult"];~typeis the branded member union.~keysis the raw value union, useful for external value-keyed records withsatisfies. Despite its historical name, it does not become the object-overload's developer-facing property-key union.~safeParseResultis the exact discriminated result returned by this declaration'ssafeParsemethod.
const = {
: "Administrator",
: "Member",
} as satisfies <(typeof )["~keys"], string>;Use derive instead when the record is part of enumwaii-controlled application behavior and source-member provenance matters.