Skip to content
This repository has been archived by the owner on Dec 1, 2019. It is now read-only.

Const enum are preserved and not replaced with actual values #137

Open
galtalmor opened this issue May 15, 2016 · 15 comments
Open

Const enum are preserved and not replaced with actual values #137

galtalmor opened this issue May 15, 2016 · 15 comments

Comments

@galtalmor
Copy link

galtalmor commented May 15, 2016

There was a change in the behavior of const enum compilation between v0.16.2 and v0.18.0.
Before upgrading my const enum values were replaced with the actual value.
Now they keep the variable name, which results in me not being able to access them from external module.
I tried to change preserveConstEnums in tsconfig.json, but nothing helps.

For example:

    const enum myEnum {
        a = 0,
        b = 1,
        c = 2
    }

    console.log(myEnum.a);

Results in:

        (function (myEnum) {
            myEnum[myEnum["a"] = 0] = "a";
            myEnum[myEnum["b"] = 1] = "b";
            myEnum[myEnum["c"] = 2] = "c";
        })(mModule.myEnum || (mModule.myEnum = {}));
        var myEnum = mModule.myEnum;

        console.log(myEnum.a);

Previously result was:

        console.log(0);
@ThaNarie
Copy link

I had a similar issue with the const enum feature.

First if all (even in 2.x), it never inlines the (const) enum values, so you will end up with:

var CallListenerResult_1 = __webpack_require__(7);
var _callListenerResult = CallListenerResult_1.default.NONE;

When preserveConstEnums is set to false (or left out) in the tsconfig.json, it will strip the export from the enum file (probably it thinks that it's inlined everywhere, so it's not needed), but due to the incorrect inlining behavior, this will result in an error.

Enum:

const enum CallListenerResult {
    NONE = 0,
}

export default CallListenerResult;

Webpack result with preserveConstEnums set to true:

function(module, exports) {
    "use strict";
    var CallListenerResult;

    (function (CallListenerResult) {
        CallListenerResult[CallListenerResult["NONE"] = 0] = "NONE";
    })(CallListenerResult || (CallListenerResult = {}));

    Object.defineProperty(exports, "__esModule", { value: true });
    exports.default = CallListenerResult;
}

Webpack result with preserConstEnums set to false:

function(module, exports) {
    "use strict";
    var CallListenerResult;

    (function (CallListenerResult) {
        CallListenerResult[CallListenerResult["NONE"] = 0] = "NONE";
    })(CallListenerResult || (CallListenerResult = {}));
}

And because there is no export, the CallListenerResult_1.default will throw a runtime error due to CallListenerResult_1 being null.

So basically, if you are using awesome-typescript-loader and (const) enums, you have to set preserveConstEnums to true in your tsconfig.json to make it output valid code.

note: it's a runtime error, so you might not notice it right away

@alexeib
Copy link

alexeib commented Jul 27, 2016

still a problem in any version > 0.17 it seems, including 1.1.1. const enums are supposed to be transpiled into their value, but instead are kept as is which causes runtime exceptions. preserveConstEnums doesnt do anything as we are not exporting the enums

@s-panferov
Copy link
Owner

Please try disableFastEmit option. Will it work?

@alexeib
Copy link

alexeib commented Jul 29, 2016

Nope, putting that into tsconfig as below does not work. Tried both 1.1.1 and 0.19.1

"awesomeTypescriptLoaderOptions": {
"forkChecker": true,
"useBabel": true,
"target": "es6",
"disableFastEmit": false
},

just to be clear i tried both true and false for disableFastEmit

@galtalmor
Copy link
Author

@s-panferov This still doesn't work in versions later than v0.16.2.
Therefor I didn't update the plug in since.
Any suggestions?

@ZenSoftware
Copy link

ZenSoftware commented Nov 2, 2016

@s-panferov I have come across this specific bug as well. It is causing me a bit of trouble with the @types/signalr types package. SignalR.ConnectionState is a const enum. Refer to: DefinitelyTyped/signalr/index.d.ts - Line 12

I have tried setting preserveConstEnums to both true and false. The results are the same for both, enums are not being replaced with their representative integer value. Instead, the variable name of the enum is left intact in the transpiled output. Resulting in code that references a non-existent object.

I should mention that I tried out a different TS compiler: gulp-typescript, and it transpiles const enum to the integer values as expected. Unfortunately it doesn't do any sort of advanced bundling like webpack.

Would there happen to exist a work-around to get awesome-typescript-loader to replace const enum with their integer values?

@vaceslav
Copy link

Any update / workaround for this issue?

@ZenSoftware
Copy link

I've tried for days to get this to work. Pretty sure there is none. It's unfortunate given how old this issue is that there is not even a hack available. It is a devastating bug after all. Think of how many code bases are incorrectly being transpiled in the wild right now because of this. I know a large portion of the Angular 2 community has been using awesome-typescript-loader.

I hate to advocate a competing loader.... but ts-loader correctly transpiles const enums. The only way we could solve this crippling issue was simply to switch.

@vaceslav
Copy link

Is it possiblle (how I can ) to change the typescript loader in angular-cli (beta 24)?

@ZenSoftware
Copy link

Oh geeze... I think I may get in trouble if I start giving directions on how to setup ts-loader here... It is extremely simple though. They drop directly in and out from one another, as they are competing loaders. http://stackoverflow.com/ may have information that you need. I think once you attempt changing it out, you will find it was surprisingly simple.

@vaceslav
Copy link

I think, I found a solution.
Enums should be defined in *.ts file/files. Not in *.d.ts file.
Then you have to import your enum.

Example:
enum.ts

export enum MyEnum {
   A = 1,
   B,
   C
}

MyComponent.component.ts


import { MyEnum} from "./enum.ts";

var foo = MyEnum.B;
switch(foo){
   case MyEnum.A:
   case MyEnum.B:
   case MyEnum.C:

}

This works with angular-cli beta 24.
tsconfig is unchanged.

@ZenSoftware
Copy link

ZenSoftware commented Dec 28, 2016

Interesting. I am glad you found something that works for you in the meantime. Although this does not solve the most crippling aspect of the bug, in that all const enum in any @type you include will not transpile correctly. Since "d.ts" files are the fundamental unit of how typing works in typescript, this is a big problem being that any "npm install @type" will not allow you to use the const enum in their definitions, and may even break the 3rd party library that you include. You really shouldn't try to hack your way around something like this. It is a far better idea to just use a correctly implemented compiler.

@vaceslav
Copy link

@ZenSoftware all you say is absolutely correct. I migrate now a project from angular2.rc2 to angular 2.3.1 + angualr-cli and for me it is show stopper when I cannot use enums. so I create multiple enums.ts files.

@squadwuschel
Copy link

any news here or solutions for this problem?

@roxteddy
Copy link

roxteddy commented Oct 9, 2017

It is blocking me as well. Any news ?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants