Description
isolatedModules
and Cross-File Enum Member References
-
"Who doesn't love enums?"
-
If you have a numeric enum member in one file, and a numberic enum that references that first one in another file...
-
...and a subsequent member has no initializer...
// foo.ts enum Foo { A = 123, } // bar.ts import { Foo } from "./foo"; enum Bar { B = Foo.A, C }
import { Foo } from "./foo"; export var Bar; (function (Bar) { Bar[Bar["B"] = 10] = "B"; Bar[Bar["C"] = 11] = "C"; })(Bar || (Bar = {}));
-
...under
isolatedModules
we don't issue an error - we don't know what this is supposed to be. -
We do when
A
is a string - and if it is, we generate avoid 0
for the initializer - but not if it's numeric (as above).// foo.ts enum Foo { A = "hello", } // bar.ts import { Foo } from "./foo"; enum Bar { B = Foo.A, C }
import { Foo } from "./foo"; export var Bar; (function (Bar) { Bar["B"] = "10"; Bar[Bar["C"] = void 0] = "C"; })(Bar || (Bar = {}));
-
Should we?
-
Probably?
-
A compiler doesn't know what it should perform - numbers get a reverse-map, strings don't.
- Well, a compiler doesn't, but runtime emit can do a dynamic check.
- Doing a lot of those is undesirable.
- You only have to do one, right?
- No, each uninitialized enum member may have to perform the same check.
- (Is this true?)
- Well, a compiler doesn't, but runtime emit can do a dynamic check.
-
Some philosophical discussion - should
isolatedModules
imply this dynamic behavior.- We won't emit these things, so how are compilers supposed to know what they should do?
- On the other hand, there is nothing preventing compilers from making these enums "work".
-
We have a few choices.
-
Force people to do the auto-numbering themselves.
// bar.ts import { Foo } from "./foo"; enum Bar { B = Foo.A, C = B + 1 }
-
Emit a dynamic check using
typeof
. -
Make a rule - enum members referencing another external enum must always be numeric, or explicitly converted to a string. Otherwise, it is an error. And under `isolatedModules``, we will have to assume nothing about the value of the enum member itself.
- So we will assume
B
is a number, and use numeric reverse-mapping emit - butC
will need an explicit initializer.
- So we will assume
-
-
Conclusion: we are leaning towards the last-mentioned rule