Ensure enum members syntactically determinable to be strings do not get reverse mappings#57686
Conversation
…et reverse mappings. Co-authored-by: frigus02 <[email protected]>
frigus02
left a comment
There was a problem hiding this comment.
Thank you, Andrew. I'm personally in favor of this approach.
Co-authored-by: Jan Kühle <[email protected]>
I personally agree with this, and so think I prefer this PR.
Is there some way we can instead use |
|
This PR moves in that direction, but we can't fully control emit by import { SomeOtherStringEnum } from './m';
enum Foo {
A = SomeOtherStringEnum.StringValue
}This works in non-isolatedModules |
|
@typescript-bot pack this |
|
Hey @andrewbranch, I've packed this into an installable tgz. You can install it for testing by referencing it in your and then running There is also a playground for this build and an npm module you can use via |
|
FWIW esbuild does it the same way this PR does so I am all for it: https://jakebailey.dev/esbuild-playground/#v3=PTAEAEDMEsBsFMB2BDAtvAXKAxge0TAOYB0AVgM74BQA3laKAERIAuATgJ4AKu0iL5RlgDajYHwAm8AB7EB0xgF0ANPSaRcbVMhZCm8cqkZUAvlSogIMBCnRZJMueWlVoqAA6aWoGqABCAIIASqAmoJBsuKigAOQARshsMQDcVEgArtEAYri4PqABoAC8oAAGACQ0gUEmpaFUQA |
|
Jake and Ryan have expressed support for this. Can I have a ✅? 😄 |
Unblocks #56736?
In #56164, we decided that under
isolatedModules, (from the notes) “enum members referencing another external enum must always be numeric, or explicitly converted to a string. Otherwise, it is an error.” This proposed rule has since undergone a number of interpretations on its way to an attempt to implement it. In #56153 (comment), Ryan stated that we should issue an error when “an enum initializer expression that isn't a string literal has a string type.” In #56736, @frigus02 worked off this statement, but interpreted “string literal” as any expression that could be evaluated to a known constant string value with single-file syntactic information only.An invariant guiding the decision is that error-free (under
--isolatedModules) code should produce semantically equivalent JS betweents.transpileModuleandtsc. Currently, that’s violated by this test case:This is currently error-free, but the emit varies.
tsc:ts.transpileModule:The problematic part isn’t the inlining of the value
"bar"; it’s the fact that the transpiled output includes a reverse mapping when it absolutely shouldn’t.To fix this, we either need an error under
isolatedModulesor we need to fix thets.transpileModuleemit. Both Ryan’s formulation of the rule proposed in #56164 and @frigus02’s expanded interpretation in #56736 make this code an error. This PR fixes the emit by determining that the initializer is definitely going to be a string without looking at any type or extra-file info.I’m fine with adopting Ryan’s very strict rule instead of this, but it does seem like fairly low hanging fruit here. I’m less of a fan of the approach currently in #56736, since constant evaluation feels like the wrong thing to control whether a reverse mapping gets created, even though that’s what actually controls the emit today.