Add -enumStyle option for erasable enum code generation#56
Merged
Conversation
Support generating const objects with union types as an alternative to TypeScript enums, for compatibility with erasableSyntaxOnly. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
4707ece to
061a0da
Compare
Add a dedicated enum schema (enum.ridl) with numeric and string enums plus errors, generate both `enum` and `union` golden fixtures, and a vitest spec verifying runtime values, drop-in type usage, and—crucially— that union mode leaves no runtime `export enum` behind (including the error enums). Wire a tests-unit vitest run into CI: it regenerates the enum fixtures from the current templates before running, so union template regressions are caught. Scoped to `generate:enum` because the pre-existing bigint `generate` (service.ridl) is incompatible with webrpc-gen v0.37.4. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
AlexanderKolberg
left a comment
Member
There was a problem hiding this comment.
This is great!
I really like this approach with the as const obj + union
Clarify the flag name ahead of a future -enumWireFormat option. "Style" reads as "how the enum is emitted in the generated TypeScript" and avoids overlap with webrpc's existing notion of an enum *type* (isEnumType) and the planned wire-format flag. Values are unchanged (enum default, union). No deprecation alias since the option is unreleased; the old -enum=... now falls through to the generic "unsupported target option" error. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
v0.27.0 and v0.28.0 were tagged without the enum feature; bump the version column to the next release this branch will ship in. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add two tsc-based tests: the union output must compile clean under --erasableSyntaxOnly, and the default `enum` output must be rejected with TS1294. This is the authoritative erasability check the text-based assertions only approximated. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The union style is mostly a drop-in replacement, but two real differences from a TypeScript enum can affect consumers: numeric enums lose reverse mapping (e.g. WebrpcErrorCodes[code]), and enum members can no longer be used directly as types (type T = Kind.USER -> typeof Kind.USER). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds a configurable
-enumStylegenerator option so users can choose how webrpc schemaenums (and the generated error enums) are code-generated in TypeScript:
-enumStylevalueenum(default)export enum— unchanged from current behaviorunionas constobject + union type (erasable, no runtimeenum)The option defaults to
enum, so existing output is unchanged unless-enumStyle=unionis explicitly passed.
Motivation
TypeScript best practices are moving away from
enumdeclarations. They emit runtimecode that cannot be erased, which is incompatible with the
erasableSyntaxOnlytsconfig option and with tooling (Node's type stripping, modern bundlers) that expects
type-only syntax to disappear at build time. The
unionstyle emits a plainconstobject plus a derived union type, leaving no non-erasable runtime construct behind.
Output comparison
Given this schema:
-enumStyle=enum(default)-enumStyle=unionIn
unionmode the same treatment is applied to the generatederrorsandWebrpcErrorCodesenums, so the entire generated file is free of runtimeenumdeclarations and passes
tsc --erasableSyntaxOnly.Caveats
The
unionstyle is mostly a drop-in replacement for anenum, with two behavioraldifferences for consumer code:
WebrpcErrorCodes[1000]returnsundefined(a numeric
enumwould return'Unauthorized'). Code mapping an error code back to itsname must be updated. Schema enums are unaffected (they use string values).
type T = Kind.USERbecomestype T = typeof Kind.USER.Changes
main.go.tmpl-enumStyleoption defaulting toenum; validate value isenumorunion, otherwise print an error and exittypes.go.tmpl$opts.enumStyle— existingexport enumblock forenum, newas const+ union block forunionerrors.go.tmpluniontreatment to theerrorsandWebrpcErrorCodesenums so union output is fully erasableREADME.mdtests-unit/enum.ridlschema + golden fixtures (enum-default.gen.ts,enum-union.gen.ts) and aenum-union.test.tsvitest spec.github/workflows/ci.ymltests-unitvitest suite on every PRTesting
tests-unit/enum-union.test.tsverifies:unionmodeexport enum, and the default output still doestsc --erasableSyntaxOnlycompiles the union fixture clean and rejects the defaultfixture with
TS1294Invalid values are rejected:
-enumStyle=foo→-enumStyle="foo" is not supported, must be "enum" or "union".