Skip to content
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

Imported const enum is not inlined in generated code #16671

Open
Jessidhia opened this issue Jun 21, 2017 · 25 comments · May be fixed by #46664
Open

Imported const enum is not inlined in generated code #16671

Jessidhia opened this issue Jun 21, 2017 · 25 comments · May be fixed by #46664
Labels
Bug A bug in TypeScript
Milestone

Comments

@Jessidhia
Copy link

Jessidhia commented Jun 21, 2017

TypeScript Version: 2.4.0

Code

// a.ts
export const enum Foo {
  Bar = 'bar'
}

// b.ts
import { Foo } from './a'

Foo.Bar // TypeError or ReferenceError, depending on how it's compiled

Expected behavior:
Foo.Bar to be replaced with 'bar'

Actual behavior:
The import is deleted and Foo.Bar is left as is

@Jessidhia Jessidhia changed the title Reexported const enum is not inlined in generated code Imported const enum is not inlined in generated code Jun 21, 2017
@DanielRosenwasser DanielRosenwasser added Bug A bug in TypeScript High Priority labels Jun 21, 2017
@DanielRosenwasser DanielRosenwasser added this to the TypeScript 2.4.1 milestone Jun 21, 2017
@rbuckton rbuckton self-assigned this Jun 22, 2017
@rbuckton
Copy link
Member

@Kovensky, I cannot seem to reproduce this behavior in typescript@next or in our 2.4 release branch. This may have been fixed by another change. Can you verify against typescript@next? If you are still seeing this, we may need more information.

@rbuckton rbuckton added the Needs More Info The issue still hasn't been fully clarified label Jun 22, 2017
@Jessidhia
Copy link
Author

It still happens with 2.5.0-dev.20170622.

It looks like --isolatedModules is causing the import { Foo } to be elided as a type import (correct), but is not replacing the Foo.Bar value in the processed source text. Disabling --isolatedModules generates correct code.

@DanielRosenwasser
Copy link
Member

Unfortunately const enums are type-directed, but emit in isolatedModules is type-agnostic (it has to be, otherwise the modules couldn't be compiled in isolation).

@DanielRosenwasser DanielRosenwasser added Working as Intended The behavior described is the intended behavior; this is not a bug Bug A bug in TypeScript and removed High Priority Bug A bug in TypeScript Needs More Info The issue still hasn't been fully clarified Working as Intended The behavior described is the intended behavior; this is not a bug labels Aug 4, 2017
@Jessidhia
Copy link
Author

If that’s the case, then perhaps it should be an error to export them to begin with (at least in non-.d.ts cases). It’s not possible to make any meaningful cross-module use of them as it is.

@pwpatton
Copy link

pwpatton commented Aug 18, 2017

in my d.ts file I declare a const enum and use it in an interface in that same file.

declare const enum LMListType {
  DEFAULT = 'default',
  SELECT = 'select',
  HELPER = 'helper',
}

interface LMListSpec {
  ...
  listType: LMListType,
  ...
}

I use it like this in my component code (angular4):
myComponent.ts:

if (this.listSpec.listType === LMListType.DEFAULT) {   
   etc...
}

Everything compiles but I get runtime errors since there is no LMListType. In-lining would fix this for me I think.

I could move my d.ts file to a regular ts file but then I have to import all of it's interfaces in each component that uses them. I'd like to avoid that.

What is suggested for this issue?

@lydia-schow
Copy link

lydia-schow commented Nov 14, 2017

I've also encountered this problem when transpileOnly: true. Without transpileOnly, I can't use multi-threading to speed up my webpack build (ts-loader, happypack, fork-ts-checker-webpack-plugin). Unfortunately, I'm dealing with +100,000 lines of legacy code, so removing all const enums is not feasible.

Typescript version: 2.6.1

@mhegazy
Copy link
Contributor

mhegazy commented Nov 15, 2017

I've also encountered this problem when transpileOnly: true. Without transpileOnly, I can't use multi-threading to speed up my webpack build (ts-loader, happypack, fork-ts-checker-webpack-plugin). Unfortunately, I'm dealing with +100,000 lines of legacy code, so removing all const enums is not feasible.

transpileOnly means transpile every file one at a time.. when the compiler is looking at one file, it has no way to know if the reference it is looking at is a const enum or not, since the declaration is in another file that it does not have access to..

so I do not think you can mix these two concepts, const enums (require whole program information), and transpileOnly (one file at a time).

@Jessidhia
Copy link
Author

Which is why I now think that exporting a const enum should be a compile error.

@mhegazy
Copy link
Contributor

mhegazy commented Nov 16, 2017

yes. it should be an error under --isolatedModules. and this bug tracks adding that.

@BehindTheMath
Copy link

@mhegazy What about under --transpileOnly?

@mhegazy
Copy link
Contributor

mhegazy commented Nov 30, 2017

Not sure what you mean, but asserting that the code is safe to transpile one file at a time is what --isloatedModules do.

@mrcrowl
Copy link

mrcrowl commented Oct 9, 2018

When --isolatedModules is specified, could const enums instead be output as regular (non-const) enums?

@Jessidhia
Copy link
Author

Either that, or they should not be allowed to be exported to begin with.

@jestarray
Copy link

jestarray commented Jan 28, 2019

Having this issue now with the vue cli. I don't know why but it was working before.. The correct settings are to turn the ts-loader transpileOnly: false and isoLatedModules: false and it should work ? Scratching my head because it was working fine until I set transpileOnly to true, which I flipped back to false but now none of it works...

//vue cli plugin typescript webpack config
 addLoader({
      loader: "ts-loader",
      options: {
        transpileOnly: false,
        appendTsSuffixTo: ["\\.vue$"],
        // https://github.com/TypeStrong/ts-loader#happypackmode-boolean-defaultfalse
        happyPackMode: useThreads
      }
    });

//exporting a const enum that aren't being inlined

export const Directions {
     UP
}

Alright, seems like mode has to be set to production. Guess I'll try to look into what happens in development later.

@bluelovers
Copy link
Contributor

bluelovers commented Jan 31, 2020

p7.zip

Version 3.8.0-dev.20200130

index.js

"use strict";

//import { Enum01 } from './temp';
//
//export const aa = {
//	a01: Enum01.A,
//}
exports.__esModule = true;
exports.bb = {
    a02: temp_1.Enum02.A
};

Enum02.A didn't emit as 0 or import temp.ts


{
  "compilerOptions": {
    "target": "ESNext",
    "module": "CommonJS",
    "isolatedModules": true
  }
}

temp.ts

//export enum Enum01 {
//	A
//}

export const enum Enum02 {
	A
}

index.ts

//import { Enum01 } from './temp';
//
//export const aa = {
//	a01: Enum01.A,
//}

import { Enum02 } from './temp';

export const bb = {
	a02: Enum02.A
}

@funder7
Copy link

funder7 commented Aug 13, 2020

Hi, what's the status of this issue? Can it be considered resolved in v3.x ?

@theonlypwner
Copy link

@funder7 No, it hasn't been resolved.

I encountered this bug with TypeScript 4.0.2. For me, it caused ReferenceError at runtime, until I disabled isolatedModules in my tsconfig.json.

@nicolo-ribaudo
Copy link

Is this still a bug? When using --isolatedModules, the original code is now compiled to

export var Foo;
(function (Foo) {
    Foo["Bar"] = "bar";
})(Foo || (Foo = {}));

so it's available at runtime.

@Neonit
Copy link
Contributor

Neonit commented May 21, 2021

Maybe related: local const enum member aliasing doesn't work either in Typescript 4.2.3 (can be observed on the official playground).

const enum N {zero, one}

import X = N;
const v0 = X.zero; // OK

import EINS = N.one; // either TS should complain here or compile it as expected

Compiles to:

"use strict";
const v0 = 0 /* zero */; // OK
var EINS = N.one; // ERROR

(Playground)

@silhouettesia
Copy link

Having this issue now with the vue cli. I don't know why but it was working before.. The correct settings are to turn the ts-loader transpileOnly: false and isoLatedModules: false and it should work ? Scratching my head because it was working fine until I set transpileOnly to true, which I flipped back to false but now none of it works...

//vue cli plugin typescript webpack config
 addLoader({
      loader: "ts-loader",
      options: {
        transpileOnly: false,
        appendTsSuffixTo: ["\\.vue$"],
        // https://github.com/TypeStrong/ts-loader#happypackmode-boolean-defaultfalse
        happyPackMode: useThreads
      }
    });

//exporting a const enum that aren't being inlined

export const Directions {
     UP
}

Alright, seems like mode has to be set to production. Guess I'll try to look into what happens in development later.

@jestarray when happyPackMode is true, transpileOnly is implicitly set to true

@jablko jablko linked a pull request Nov 3, 2021 that will close this issue
@jablko
Copy link
Contributor

jablko commented Nov 3, 2021

I think this issue can be marked fixed (since #40499):

@andrewbranch
Copy link
Member

It seems like we’re in a better place now with additional errors and isolatedModules implying preserveConstEnums, but I don’t see why isolatedModules should also prevent inlining const enums. The purpose of the flag is just to check that code can be transpiled one file at a time. There’s no reason, as far as I can tell, to make the emit worse when you’re doing whole-program compilation with tsc.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug A bug in TypeScript
Projects
None yet
Development

Successfully merging a pull request may close this issue.