Proposal: "plain-enums" option to output TypeScript enums usable at runtime - #128
Merged
Merged
Conversation
const enum members are inlined by the TypeScript compiler and produce no runtime object, so consumers can't read enum values at runtime (e.g. Object.values()). Add a plainEnums parameter, defaulting to false, so the writer can emit a plain export enum instead when runtime access is needed.
WriteEnumConst's new plainEnums parameter needs a path from the command entrypoint down to where enums are written. Wire it through Generator, GenerateCliOutput, and GenerateJsonOutput the same way useEnums already reaches both output paths.
Exposes the plainEnums behavior through the same config-or-CLI pattern as every other option. I considered making use-enums itself a three-way value (object, const, plain) instead of adding a second boolean, since that would make the one meaningless combination (use-enums off, plain-enums on) unrepresentable. I kept use-enums as a plain boolean and added a modifier instead, because it's an existing public flag and every other option in this package is a flat boolean; changing its type would mean true/false permanently carry legacy meaning while new string values mean something else. I defaulted plain-enums to false rather than adding a const-enums flag defaulting to true, because every boolean flag here is a presence-only Artisan option with no --no-flag negation. A default-true flag could be turned on redundantly from the CLI but never off, forcing anyone who wants plain enums to edit the published config file instead of just passing a flag.
Adds direct coverage for both branches of the useEnums=true path, alongside a new test for plainEnums. The const enum branch was previously only exercised indirectly through the full command, so this pins its output at the unit level too.
Confirms the flag reaches generated output through the full command, mirroring the existing use-enums command-level test.
Adds it to the Additional Options list and extends the existing const enum note to explain why it isn't readable at runtime and how --plain-enums opts out of that.
Member
|
this is great! i'm wondering if that should just be the default behavior? but i think for now id rather not introduce that for a minor version change. so how this is proposed now with the opt in seems like a good path to me |
tcampbPPU
approved these changes
Aug 1, 2026
Contributor
Author
Awesome! And I think making that the default behavior would make sense too, I just went with this path to avoid any breaking changes to existing configs 😅 Maybe you could invert the option to be called Anyway, thanks for merging! |
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.
First off, thanks again for building and maintaining this package. I've been using it extensively, and it's worked great for keeping my TypeScript types in sync with my Eloquent models.
This PR is a proposal for a small addition that would help me integrate ModelTyper's output more fully into my TypeScript code, and I'd love feedback on whether it fits the direction you want for the API.
Problem
--use-enumscurrently always emitsconst enum.const enummembers are inlined by the TypeScript compiler, so they don't produce a real object at runtime, they only exist as a compile-time construct. That means I can't do things likeObject.values(Roles)on the generated enums in code that uses ModelTyper's definitions.Proposal
I propose adding a
--plain-enumsflag (and matchingplain-enumsconfig key) that, when used together with--use-enums, emits a plainexport enuminstead ofexport const enum. A plain enum compiles to a real object, so its values are readable at runtime. Defaults tofalse, so nothing changes unless it's explicitly opted into.Design choices
Please let me know if you disagree with any part of the approach, and I can adapt it to your vision for the package.
First, I used a new boolean flag, trying to match the existing options in the project. I considered making
use-enumsa three-way value (something likeobject/const/plain) instead, which would avoid the one meaningless combination (use-enumsoff,plain-enumson). I went with a new boolean flag instead becauseuse-enumsis an existing flag used by consumers, so I'd rather not create something backward-incompatible. Also, most other options in this package are boolean and read the same way, so I tried to keep that consistent. Changinguse-enums's type felt like a bigger, riskier change than this PR needed to make, but I'm open to going the other direction if you'd rather have one option.Second, I chose to default to
false(opt-in) rather than make it aconst-enumsflag defaulting totrue. Every boolean flag in this package is a presence-only (--flag) CLI option (no negative--no-flagoption). A flag defaulting totruecould not be turned off from the CLI without deviating from the other flags. Making the new behavior opt-in keeps it usable from the CLI alone, without needing to edit the config file, and being consistent with other flags.Changes
src/Actions/WriteEnumConst.php: emitsexport enuminstead ofexport const enumwhenplainEnumsis setsrc/Actions/Generator.php,GenerateCliOutput.php,GenerateJsonOutput.php: drill the new option through, alongsideuseEnumssrc/Commands/ModelTyperCommand.php,config/modeltyper.php: new--plain-enumsflag and config keyWriteEnumConst, for bothconst enumand plainenum) and the full commandreadme.md: documents the new flagI am happy to adjust naming, defaults, or the scope based on your feedback.
Related
#54 asks for something similar but in the default (non
--use-enums) object-literal path: exporting theconst X = {...} as constobject itself so it can be used directly at runtime, not just its derived type. This PR doesn't touch that path, it's specifically about theconst enumissue on the--use-enumsside, but I wanted to flag it as related since the underlying motivation (using generated enum-like values at runtime) is the same.