Skip to content

const enum is broken #2741

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
khoden opened this issue Oct 17, 2016 · 21 comments
Closed

const enum is broken #2741

khoden opened this issue Oct 17, 2016 · 21 comments
Labels
needs: investigation Requires some digging to determine if action is needed

Comments

@khoden
Copy link

khoden commented Oct 17, 2016

OS?

Mac OSX Sierra

Versions.

1.0.0-beta.17

Repro steps.

ng new --prefix=t check-enum
cd check-enum/
ng serve

then add to main.ts (no matter, may be any *.ts)

declare namespace Sts {
  export const enum A{
    a, b, c
  }
}
console.log(Sts.A.a, Sts.A.b);

The log given by the failure.

main.bundle.js:65131 Uncaught ReferenceError: Sts is not defined

Actual in main.bundle.js

console.log(Sts.A.a, Sts.A.b); (see at Source panel of Chrome Developer Tools)

Expected in main.bundle.js

console.log(0 /* a */, 1 /* b */);

If I run tsc from src directory, this code will be in dist/out-tsc, as expected. TypeScript is OK!

Mention any other details that might be useful.

I donn't know, where is a mistake, in angular-cli or its configuration or deps. Generated code is same, as without const keyword. This is very strange.

@filipesilva filipesilva added the needs: investigation Requires some digging to determine if action is needed label Oct 17, 2016
@zhengbli
Copy link

zhengbli commented Feb 9, 2017

This is blocking me as well. version 1.0.0-beta.25.5

@zsparal
Copy link

zsparal commented Apr 9, 2017

We also ran into this while upgrading to a Webpack-based/AOT-enabled build system. We have some tooling set up that automatically generates d.ts files for all of our web-facing model classes. This maps native enums - very correctly - to const enums.

The automatically generated .d.ts file:

declare module server {
    const enum Status {
        OK
    }
}

The problem arose when we tried to use these enum values directly:

export function processStatus(status: server.Status) {
    switch (status) {
        server.Status.OK:
            // Custom code here
            break;
    }
}

Luckily code like this was few and far-between so I solved the issue by replacing the generated enums with their constant values. This solution is of course very far from ideal: we lose type safety and the code becomes harder to read. Non-ambient const enums are properly transpiled.

Since this issue is 6 months old and is a pretty severe codegen bug some official word would be really appreciated.

@khoden
Copy link
Author

khoden commented Apr 18, 2017

It still be very annoying bug.
Did anybody try to fix or "investigate" this?

@khoden
Copy link
Author

khoden commented Apr 18, 2017

I found explanation: Const enums are preserved when using transpileModule

In short: transpileModule compiles in single-file mode, so it don't know about enums in other files.

@khoden
Copy link
Author

khoden commented Apr 18, 2017

Now I don't use const enums(

preserveConstEnums = true not works in ambient declaration files (*.d.ts)

Third way is too complex and takes much time. It is very expensive in support.

Thanks!

@demyanets
Copy link

Dear CLI team! Please give some feedback on the issue.
I have similar setting as Gustorn (post from 10 Apr.) and feel very uncomfortable modifing generated code just to satisfy the CLI tooling pipeline.
"awesome-typescript-loader" still does not have any solution for the problem, so may be you can replace the loader?
Thanks!

@sumitarora
Copy link
Contributor

@taras-demyanets @khoden You can compare enums using valueOf function of enums.

namespace Validation {
  export const enum A {
    a, b, c
  }
}

const x: Validation.A = Validation.A.c;
console.log(x.valueOf() === Validation.A.b); // return false

switch (x.valueOf()) {
  case Validation.A.a:
    console.log('a');
  break;
  case Validation.A.b:
    console.log('b');
  break;
  case Validation.A.c:
    console.log('c');
  break;
  default:
    console.log('none');
  break;
}

@sumitarora sumitarora self-assigned this May 11, 2017
@zsparal
Copy link

zsparal commented May 12, 2017

@sumitarora The problem isn't that we can't compare const enums, it's that the values we're comparing against aren't transpiled (and thus result in runtime errors). If we take your example (a little shortened):

// Ambient declaration in another .d.ts file
namespace Validation {
  export const enum A {
    a, b, c
  }
}

// Usage code
const x: Validation.A = Validation.A.c;
switch (x.valueOf()) {
  case Validation.A.a:
    console.log('a');
    break;
}

Should transpile to:

var x = 2;
switch (x.valueOf()) {
    case 0:
        console.log('a');
        break;
}

But instead transpiles to:

var x = Validation.A.c;
switch (x.valueOf()) {
    case Validation.A.a:
        console.log('a');
        break;
}

And naturally it cannot find Validation.A.c and Validation.A.a at runtime.

@squadwuschel
Copy link

squadwuschel commented May 20, 2017

I've many enums in my project and that I can't use them is a really show stopper for me to use the cli.

Currently I am using pure webpack 2 and there everything is workingfine with the Enums here my TS loader is the following rule

test: /\.ts$/,
       use: [
         '@angularclass/hmr-loader?pretty=' + !isProd + '&prod=' + isProd, 
         'awesome-typescript-loader',
         'angular2-template-loader'
     ],

I have a .NET MVC Project and I am using TypeLite to generate TypeScript Enums out of my C# Enums. Here a Enums.ts file is created with many Enums inside like

module  Internal.Notification.DomainModel {
  export const enum NotificationType {
	Information = 0,
	Success = 1,
	Warning = 2,
	Error = 3
   }
}
module  Internal.Repository.DomainModel {
  export const enum SortDirectionEnum {
	Ascending = 0,
	Descending = 1
   }
}

I am currently trying to migrate from my own webpack 2 build to the cli but currently it seems not possible.

@imiuka your Solution with "preserveConstEnums" is not working here and the third solution is too complex, there I can stay with my current own WebPack Build Setup.

@Gustorn why is the third Solution from @imiuka not implemented in the CLI with an addional Parameter or so and perhaps can someone explain me why my TypeScript Loader setup makes no Problems with the Enums?

A working solution for such a common problem would be really nice.

@wsquire
Copy link

wsquire commented May 24, 2017

This is still a blocking issue for me.
Repro steps:

  • create a new project (ng new)
  • add a new ts file (enums.ts for example)
  • make the contents of this file
    module enums { export const enum myEnum { value0 = 0 } }
  • add this file to the tsconfig.app (using "files" or "include" for example)
  • reference your enum in app.component.ts
    let x = enums.myEnum.value0;
  • ng serve (or test or e2e)

Expected:
The app builds and runs without error
Actual:
The app builds without error. However, the module containing your enum will not be defined at runtime. Error message: Uncaught ReferenceError: enums is not defined.

The module not being defined at runtime is actually expected. The compiler should have replaced the enum reference with the value because this enum is defined as a constant. This is unexpected and undesirable behavior.

This issue prevents me from using angular-cli in projects where I have split out enumerations into their own files for reuse. What is worse is that I can not use tools like typelite to automatically translate my enumerations from .Net to typescript.

@angular/cli: 1.0.4
node: 6.10.2
os: win32 x64
@angular/common: 4.1.3
@angular/compiler: 4.1.3
@angular/core: 4.1.3
@angular/forms: 4.1.3
@angular/http: 4.1.3
@angular/platform-browser: 4.1.3
@angular/platform-browser-dynamic: 4.1.3
@angular/router: 4.1.3
@angular/cli: 1.0.4
@angular/compiler-cli: 4.1.3

@zsparal
Copy link

zsparal commented May 24, 2017

The worst thing is that this is a solved problem in ts-loader. I understand the desire for higher performance (transpileModule is faster) but at least add an option for us to use the slower but correct version.

As a temporary workaround you can actually import const enums explicitly and it will work as expected. The problem is that most tools generate definition - and not regular - TS files.

@wsquire
Copy link

wsquire commented May 24, 2017

Indeed.

As for the workaround, I agree that explicit importing should work for cases where I we modify the source file. AFAIK we would have to modify that enums file to start with export module enums .... Is there a way to explicitly import a file which does not export?

This is the crux of the issue with Typelite. The enum file generated by Typelite has a structure just like in my steps. I believe I can not explicitly import a Typelite enum since it is generated and, as far as I can tell, there is no way to alter how the module is declared when it is being generated.

@lordzero83
Copy link

We want to use CLI in out current project for better updateability, but could not switch due to the enum problem.
We also use Typlite to generate our enums.

Is there anybody investigating this problem and can say when the problem will be solved?

@khoden
Copy link
Author

khoden commented Jun 7, 2017

@lordzero83 I found the reason: #2741 (comment)

It's need for performance. Each ts file compiles separately, without information from other files. While transpileModule is used, the trouble stays.

@zsparal
Copy link

zsparal commented Jun 7, 2017

The thing is, ts-loader with its fork-checker-plugin beats awesome-typescript-loader in some of our projects and it actually generates correct code.

@squadwuschel
Copy link

squadwuschel commented Jun 9, 2017

@khoden it would be great if the cli could provide a configuration parameter, where it ignores the performance improvements so that you can use the cli also with const enums (TypeLite) and a slower performance would be ok for me.

@MikeMatusz
Copy link

This is a major issue for us, as well. The fact that it's a runtime error makes it even worse because it's really easy to miss. @hinaria , what webpack plugin are you using to do the replacement?

@ghost
Copy link

ghost commented Sep 2, 2017

This seems to still be an issue but in a different way, and it's causing issues in other module repos: swimlane/ngx-datatable#927

@clydin
Copy link
Member

clydin commented Jan 5, 2018

With CLI 1.5+ and Angular 5, the use of transpileModule has been eliminated. Note that Angular 4 uses the previous compiler pipeline so if const enum support is required please update to Angular 5+.

@josephliccini
Copy link

Tested this out and it works! Thanks for fixing it 👍

@angular-automatic-lock-bot
Copy link

This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.

@angular-automatic-lock-bot angular-automatic-lock-bot bot locked and limited conversation to collaborators Sep 9, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
needs: investigation Requires some digging to determine if action is needed
Projects
None yet
Development

No branches or pull requests