TypeScript Version: 2.6.2
Code
//package.json:
{
"name": "issue-ts-isolatedmodule",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"jquery": "^3.2.1"
}
,"devDependencies": {
"typescript": "^2.6.2",
"@types/jquery":"^3.2.17"
}
}
//tsconfig.json
{
"compilerOptions": {
"outDir": "build/dist",
"module": "esnext",
"target": "es5",
"lib": ["es6", "dom"],
"sourceMap": true,
"allowJs": true,
"jsx": "react",
"moduleResolution": "node",
"rootDir": "src",
"forceConsistentCasingInFileNames": true,
"suppressImplicitAnyIndexErrors": true,
"isolatedModules": true,
"preserveConstEnums": true,
"preserveSymlinks": true,
"allowSyntheticDefaultImports": true
},
"exclude": [
"node_modules",
"build",
"scripts",
"acceptance-tests",
"webpack",
"jest",
"src/setupTests.ts"
]
}
//src/index.ts
export function HalloWorld(){
return "Hallo world!"
}
Executing tsc -p ..
Expected behavior:
successfully compiled /build/dist/{tsfilename}.js for each ts module:
Actual behavior:
node_modules/@types/jquery/index.d.ts(7690,16): error TS1209: Ambient const enums are not allowed when the '--isolatedModules' flag is provided.
node_modules/@types/jquery/index.d.ts(7698,16): error TS1209: Ambient const enums are not allowed when the '--isolatedModules' flag is provided.
@mhegazy I was discussing this with Skype earlier this week - it would be much better if const enum was only an error if consumed in an implementation file. Otherwise random .d.ts files from DT can "poison" --isolatedModules compilations. Thoughts?
If it is consumed by a ts file, how to use JQuery types with --isolatedModules on?
I have created a dtslint issue to ban const enums in declaration files. i think a declaration file in general should be applicable to the strictest settings, and this includes --isolatedModules.
We need to expand the lint rule on DefinitelyTyped as const enum on DT really does not make sense.
Separately, accepting PRs to move the error from a const enum existing to a const enum being referenced (in a value position) when isolatedModules is on. Should be relatively easy.
const enumon DT really does not make sense.
@RyanCavanaugh const enum in an ambient context allows documenting a set of values which are not available via the object model, and which are to be inlined on compilation. Instead of this:
const app = new ActiveXObject('Access.Application');
app.RunCommand(97); // what is 97?
the enum values could be defined in the .d.ts file:
declare namespace Access {
const enum AcCommand {
// ...
acCmdSaveRecord = 97,
// ...
}
}
and consumed by the .ts file by name:
app.RunCommand(Access.AcCommand.acCmdSaveRecord);
and inlined on compilation.
Ideally, these values should be part of the object model:
// Javascript implementation code
var Access = {
AcCommand: {
acCmdSaveRecord: 97
}
};
and could then be referred to in the .d.ts file as a plain (non-const) enum; but I don't think this is done in practice.
Perhaps this isn't the best mechanism for inlining declared values, as enum doesn't just imply a documented set of values, but also restricting to that set of values. But the compiler doesn't enforce this; the following would compile:
app.RunCommand(-42);
even though -42 is not one of the values used in the enum.
const enum in an ambient context allows documenting a set of fixed values to be inlined on compilation, which are not accessible via the object model. Instead of this:
You should use a union type of literals (string or number) instead.
I understand the documentation rational. but a declaration file is included in multiple projects, and the author of the declaration can not control how the user will build their project. And thus, a .d.ts should adhere to the least common denominator of compiler options. this is not any different from --noImplicitAny or --strictNullchecks.
@mhegazy
a .d.ts should adhere to the least common denominator of compiler options
Understood. My question is now, why does --isolatedModules prevent inlining values from const enums?
The flag is meant to support transpiling a single file at a time. i.e. the whole project is not loaded when a file is transformed. and thus the compiler does not have access ot the .d.ts file to find out what values to use.
@mhegazy I must be missing something here -- so how can anything from the .d.ts file be enforced?
tsc --isolatedModules processes the whole project. it errors if it is not safe to transpile this project one at a time.
Consider for example using babel to transpile a TS project. you would run tsc as a type checker only, but not as a transpiler. babel only transpiles one file at a time, and has no way to get access to the .d.ts.
hope this explains it.
@mhegazy Yes, thanks.
I have the same error with chalk and @types/range-parser in node_modules. I cannot change them, and use babel with @babel/preset-typescript, any plans on fixing this ? How can I help ?
Same problem with @types/big.js and @babel/preset-typescript
Is replacing const emuns by string union types in DefinitelyTyped repo the only way to fix this error?
@chicoxyzzy Did you find out what's the best practice to handle this problem?
@chicoxyzzy @noelyoo You can disable the no-const-enum rule in your tslint.json, like this.
@zspitz
Disabling the no-const-enum rule does not solve this problem:
Failed to compile.
/Users/noel/react-auth-demo/node_modules/monaco-editor/esm/vs/editor/editor.api.d.ts h-demo/src/containType error: Ambient const enums are not allowed when the '--isolatedModules' flag is provided. TS1209
@noelyoo my workaround has been to remove isolatedModules from my config and just be really careful not to use const enums in my project or from third-party libraries, and to set up my build system to compile modules independently anyway.
I think the best long-term solution is https://github.com/Microsoft/TypeScript/issues/20703#issuecomment-361434795 (making isolatedModules prohibit you from using const enums rather than prohibiting you from using libraries that have a const enum anywhere in their typedefs). Another solution is to be better about getting library authors to publish types that are isolatedModules-friendly, but it seems like there are a lot of const enums in the wild and not a lot of awareness of this issue in the first place.
@alangpierce @chicoxyzzy I solved the above issue by setting skipLibCheck as true in tsconfig.json based on ianschmitz's suggestion.
I put up a PR to change the error to happen when accessing an ambient const enum rather than declaring one (https://github.com/Microsoft/TypeScript/issues/20703#issuecomment-361434795), which should pretty much make this a non-issue: #28465.
Hoping it will be available in the next 1.3.7 distributive. This error is showstopper for us.
I was able to resolve this myself by applying the change I made in this PR with patch-package to override the official @types/ package. This approach can be used to work around the issue for other libraries with outdated types too.
Most helpful comment
I have the same error with
chalkand@types/range-parserin node_modules. I cannot change them, and use babel with@babel/preset-typescript, any plans on fixing this ? How can I help ?