Typescript: "Cannot compile namespaces" error with --isolatedModules and no namespaces

Created on 17 Apr 2017  路  52Comments  路  Source: microsoft/TypeScript

TypeScript Version: nightly (2.3.0-dev.20170417)

Code

function f() {}

Expected behavior:

No error, or an error message about a non-module file in an --isolatedModules project.

Actual behavior:

src/a.ts(1,1): error TS1208: Cannot compile namespaces when the '--isolatedModules' flag is provided.

This occurs because we in program.ts verifyCompilerOptions to look for any source file that isn't an external module declaration, and fail on the first one, whatever it may be.
The error message should be upgraded to reflect the real reason we issue this error, and not mention namespaces.
Alternately, we could just allow files without imports and actually look for a namespace before adding this error.

Bug Error Messages help wanted

Most helpful comment

A global file cannot be compiled using '--isolatedModules'. Ensure your file contains imports, exports, or an 'export {}' statement.

All 52 comments

The error message needs to be clearer. instead of namespaces it can say non-module. @DanielRosenwasser recommendations?

There should not be an error message in this situation. The --isolatedModules option should just turn off the internal module system completely, if tsc still errors out this way then the option didn't do its job.

In #15839 I intended to modify the checking behavior but later realized that this check is just pointless and the ideal solution is to remove it.
Typescript has always allowed usage of namespace inside an external module with --isolatedModules on:

export function something() {} // export found, so this module is considered 'external'
namespace ns {} // namespace is still valid in an external module

Thus the check isn't doing anything in that (seemingly invalid) case, when it's supposed to complain. So why complain when the programmer isn't even using any namespace, doing nothing wrong?

@wilonth The reason for this issue is that the error message is wrong: namespaces are perfectly fine if part of a (es6) module, but any non-module file should be an error.

@andy-ms I was trying to point out that the whole code to check for this error is just pointless, and we should just remove it instead of complicating the code more.
My point is, when --isolatedModules is on, every file should be regarded as an external (ES6) module, period. In that sense, usage of Namespaces should be legal because right now, it is perfectly legal to use Namespaces inside ES6 modules (with --isolatedModules on).

My point is, when --isolatedModules is on, every file should be regarded as an external (ES6) module, period.

The semantics here is that a module is a file with at least one top-level import or export. it does not matter how you invoke the compiler.

@mhegazy Yes and that rule is exactly the root of the problem we have here. The rule unfairly treats a file without import or export as a part of the legacy internal module system, so --isolatedModules rejects the file.
Now we should not change the rule because that will probably break a lot of things, but we can solve the current issue very easily just by removing this error message.
Let's imagine this "cannot compile namespaces" error message being removed, what could go wrong? What about a codebase that uses internal module, like the Typescript compiler itself? With --isolatedModules on, would it compile to garbage code and confuse the user? No it won't, there would be a lot of Typescript error messages about undefined symbols, because --isolatedModules broke the links between the files, pretty obvious to understand.
Can you find ANY downsides with removing this error message? I couldn't. Why wouldn't we choose the easiest solution, that involves zero work (just remove the lines) and has no downsides?

With --isolatedModules on, would it compile to garbage code and confuse the user? No it won't

Yes, it will.

The point of the --isolatedModules flag is to validate that a program can be successfully compiled through single-file transpilation.

The TypeScript codebase can't be successfully compiled through single-file transpilation. There is code like this everywhere:

file1

namespace ts {
  export var x = 10;
}

file2

namespace ts {
  var y = x; // transpiles to ts.x during whole-program compilation
}

If we single-file transpiled file2, it would break.

My bad, I screwed up my testing. I hereby retract my proposal. Thank you @RyanCavanaugh for reminding.

So the solution should be: detect real namespace usage before throwing out this error message (i.e the "alternative" solution that @andy-ms proposed). We can't just change the text to something else because an error message in this case is totally wrong.
I want to make a PR, but can I still be trusted here after spewing out all those bullshit?

A global file cannot be compiled using '--isolatedModules'. Ensure your file contains imports, exports, or an 'export {}' statement.

If we single-file transpiled file2, it would break.

Sorry for the necromancy, but surely this should, when targeting modules, fail with something like 'x' is not defined? That case doesn't seem any different to me to the trivial:

file1

var x = 10;

file2

var y = x;

Which also works when concatenating/globally evaluated and not with modules; nothing to do with namespaces.

Essentially, why does typescript bother guessing that files without import or export are not modules, when it should already know from the module compiler option? E.g. Typescript itself compiles without setting module, so it is using the default none, so the compiler can assume concatenation/global evaluation.

When using --module <something> and using un-imported declarations from other files, (including namespaces themselves) typescript will already fail with "not defined" before --isolatedModules, and the same after with the export {} workaround, so this doesn't seem like a compatibility break to remove this guess - am I missing something?

I did notice that for some reason you can still use import/export with --module none --isolatedModules, which is rather confusing, possibly a bug?

@DanielRosenwasser as an end user: what does "A global file" mean? I like the guidance though. Perhaps more like "Files without any import or export statements are not modules, and cannot be compiled with '--isolatedModules'. Add an 'export {}' statement if this file is only evaluated for it's side-effects." - though the language there doesn't seem very error message-y.

I'm seeing same error for a simple js project. I have just created a sample js project below are the package and script files content. How can I resolve this issue?

Package.json
{
"plnkr": {
"runtime": "system"
}
}

lib/script.js
//
//Blackjack
//by Dheeraj Kumar
//

let card1 = "Ace of spades",
card2 = "ten of Hearts";

console.log('Welcome to Blackjack!');

console.log("You are dealt: ");
conosle.log(" " + card1);
console.log(" " + card2);

Any updates on this?

I often find myself doing this in small tests.

describe('jest', () => {
  it('finds this test', () => {
    expect(true).toBeTruthy();
  });

  it('parses this typescript', () => {
    const actual: number = 0;
    const expected: number = 0;
    expect(actual).toEqual(expected);
  });
});

export {
  // Use an empty export to please Babel's single file emit.
  // https://github.com/Microsoft/TypeScript/issues/15230
}

I really want an option that causes TypeScript to consider every .ts file as an ES6 module, regardless of whether it contains import/export statements or not. I originally assumed the --isolatedModules option was that option, but it causes this extremely confusing error on import/export-less files. (I still don't understand what the error message means by namespaces. I don't think I'm using that feature.) The reason I want this setting is because I've had several issues go uncaught by TypeScript because I accidentally referenced a top-level variable from one .ts file in another (which both didn't have import/export statements, so TypeScript didn't treat them as ES6 modules) despite using node/parcel/webpack where files can't reference each other's unexported variables like that.

I wound up here while trying to fix a sort-of-related annoyance. Comments below are just to help any other VS Code users searching about this error with create-react-app and TypeScript.

When configuring a proxy with create-react-app 2.x and TypeScript, you add a file named setupProxy.js with code like this:

const proxy = require('http-proxy-middleware');
module.exports = function(app) { /* ... */ };

react-scripts reads this file outside of the ts transpilation process, so it must be plain js.

This works exactly as documented, but it has an annoying side effect.

The tsconfig.json generated by react-scripts includes all files in src, including setupProxy.js. As a result, it triggers VS Code to show the Cannot compile namespaces... error in setupProxy.js, mark the code with a red squiggle and include it in the Problems pane. In my setup, it also highlights the file and all its ancestor folders in red.

Solution: Suppress the VS Code error message by excluding the setupProxy.js file in tsconfig.json.

{
  // ...
  "exclude": ["src/setupProxy.js"]
}

react-scripts forces isolatedModules: true, but it doesn't appear to overwrite exclude.

Alternative: Add a named export to `setupProxy.js:

export const _ = '';

With a top-level export, it's now valid with --isolatedModules.

Very often developers get this message because there are file that should be not included into copliation (gulp.js etc)

ATTENTION - If you are using a create-react-app and you see this issue like I am... I was able to bypass this by making a change to my tsconfig.json file....

Changing the following

    "isolatedModules": true,

to

    "isolatedModules": false,

@UncleFifi And then the error moves from the type-check to the babel typescript transform, see the first caveat.

@jtbennett you can just export nothing at all with export {}; - the degenerate form of export { name, localName as exportName };

@UncleFifi And then the error moves from the type-check to the babel typescript transform, see the first caveat.

Only if you're actually using namespaces. This issue is mainly about this error complaining about namespaces comes up when you're not even using namespaces and just happen to have a legal file with import/export.

Only if you're actually using namespaces. This issue is mainly about this error complaining about namespaces comes up when you're not even using namespaces and just happen to have a legal file with import/export.

Right, sorry - it's been a while since I read this thread! That said, the reason they set --isolatedModules in CRA is because it closely emulates the limitations of babel typescript (since babel is single-file transpilation too), so you should at least be aware that you are removing that guard-rail.

So, is the current solution to error Cannot compile namespaces when --isolatedModules flag is provided to add export {}; at the top of the file?

Yes, that will work around the issue. (Assuming you're not actually using TypeScript namespace. Otherwise you have a different and probably legitimate issue.)

Just ran into this message due to a file an "empty" file (i.e. the whole file was commented out). I'm happy TS caught this, but the error message was extremely opaque (and the colors were broken on a vanilla CentOS 7 Install, but this probably due to the webpack dev server, not related to TS directly)

screen shot 2019-02-06 at 14 20 14

_Edit: can鈥檛 reproduce. I definitely was staring at the file consisting of only three top-level exports and I had this error, but learly, I did something wrong somewhere else._

This error just happened to me with a file that does have top-level exports.

// Cannot compile namespaces:
export const foo = 'foo';

// Compiles fine
const foo = 'foo';
export { foo };

@denis-sokolov Obvious question: do you also have other stuff in that file, such as namespaces?

If it's literally just the export const, my second guess would be that typescript is being used in something like webpack with ts-loader, and is only seeing the content after previous pass (e.g. babel-loader) that is expanding export in some way, but that's a bit of a stretch.

I am unable to reproduce it anymore. Sorry, @simonbuchan, for the false alarm.

No idea why i'm getting this error on that specific file.
Other files behave fine

screen shot 2019-02-18 at 12 49 07
screen shot 2019-02-18 at 12 48 34

I am in a situation where I am using CRA TypeScript and importing a package which has no @types. I want to add a declare module 'package' to provide my own types, but I cannot put this statement in any module file. So I go ahead and create types.ts to place the declare module statement there. Now I get this error.

When I override isolatedModules to false, CRA changes it right back for me. That's not a solution.

When I add export {} to the types.ts file with declare module, I get Invalid module name in augmentation. instead. This error is avoided by putting the declaration in a non-module file, but CRA through this forced isolatedModules setting forces every file to be a module!

So there is a circular path of solving one error only to land on another and back. How can this be resolved?

@Bnaya at a guess, the files that work are using import or export statements? Only use one of require()/module.exports and import/export in your code. Otherwise, check that all your files are covered by the tsconfig include (check the docs for full detail on that

@TomasHubelbauer Module declarations should be in a .d.ts for this reason, amongst others.
I only had CRA re-add settings I removed, not change them back, but perhaps it's more insistent for isolatedModules?

@simonbuchan I tried a .d.ts but that didn't work for me either, I will report back with why exactly, not sure what it was. And indeed CRA rewrote that setting for me.

@simonbuchan i've tried all the above before hand - no avail :(

@simonbuchan Hmm okay so .d.ts works, I can declare the module there and type it. The reason I originally abandoned it is because for those typings I want to declare in that module, I need to reference other typings, but introducing import in the .d.ts file causes it to stop working. I do not know how to resolve this, but that is my lack of TypeScript knowledge which no longer has anything to do with this error.

Here's a minimal repro case, using typescript@next (full repo at https://github.com/yang/sandbox-ts-namespaces-error):

src/a.js: (notice, no import/export keywords needed)

module.exports = "hello"; // you could really put anything here, e.g. console.log('hello');

tsconfig.js:

{
  "compilerOptions": {
    "allowJs": true,
    "isolatedModules": true,
    "noEmit": true,
    "strict": true
  },
  "include": ["src"]
}

Error:

$ ./node_modules/.bin/tsc
src/a.js:1:1 - error TS1208: Cannot compile namespaces when the '--isolatedModules' flag is provided.

1 module.exports = "hello";
  ~~~~~~


Found 1 error.

I too first encountered this via create-react-app --typescript, which instructs you to create a setupProxy.js (or setupTests.js). CRA also sets isolatedModules and allowJs to true. It seems to have not been an issue until a more recent typescript version (I didn't see errors about setupProxy.js while on typescript 3.1.x, only after updating to 3.2.x or 3.3.x).

The workaround of adding .js files to your exclude set works when running tsc, but - annoyingly - you still see errors from those files in editors from the TS language service (tried both VS Code and Webstorm). (This seems to be a separate and more general issue with the TS language service not respecting excludes - but I wasn't able to find an existing issue for that.) To mask this error in the editors, I added .d.ts files for the *.js files.

Furthermore, require-ing or import-ing the .js files renders the exclude ineffective as well, causing the error to be raised (outside your editor).

Only disabling allowJs (against what create-react-app suggests) seems to be working for me.

I keep getting this error for my web worker.

I have tried excluding the individual file or folder and it isn't working for me.

Is there no way to override this isolatedModules setting, CRA keeps rewriting the tsconfig.json.

Any other suggestions?

@jamespfarrell Put export {}; somewhere in your file.

@Macil thanks for your advice.

I get this error:

Attempted import error: './workers/HeartBeat.worker.js' does not contain a default export (imported as 'HeartBeatWorker').

If I add:

export default {};

I get:

Uncaught TypeError: _workers_HeartBeat_worker_js__WEBPACK_IMPORTED_MODULE_2__.default is not a constructor

Isn't there simply a way to bypass this 'isolatedModules' if not for one file, even for all files?

Those errors you're getting now are unrelated to the isolatedModules setting. If you turned off isolatedModules, you'll still get those errors.

Attempted import error: './workers/HeartBeat.worker.js' does not contain a default export (imported as 'HeartBeatWorker').

Where is this error happening? It sounds like you're trying to import the default export of a file that doesn't have one, like import Foo from './workers/HeartBeat.worker.js';. If you don't want to import a default export, then change your import line to import './workers/HeartBeat.worker.js';.

You're right it was something else @Macil ! thanks!

_Maybe somebody else will have the same issue:_ I had the same error appearing for a few files I've left as placeholders with no content in them but I've been importing them in other files, ie. I had empty styles.js file which was imported in another component file.

Just add
image

I had this error for a module definition that I accidentally suffixed .ts instead of .d.ts, if anyone else is making that particular mistake. Have to restart server after fixing.

Same error. I am using CRA

Faced this issue on CRA. I was simply forget to export anything from the file:
小薪懈屑芯泻 褝泻褉邪薪邪 芯褌 2019-04-22 22-24-04

So I had this error because I had a .js file in the root folder of my project, in my tsconfig.json file I had this configured:

"compilerOptions": {
    ....
  },
  "include": ["src"],

I had to switch it for this:

"compilerOptions": {
    ....
  },
  "include": ["src/*"],

That fixed it, but I don't understand why, can someone explain it to me? My understanding was that including src would eliminate root files and sibling folders.

@thitemple Did you get that /* snippet from an article somewhere? The webpack manual seems to indicate that the first one is the correct one. I'm diagnosing a similar problem and came across your post.

@vort3xxx I did not. I saw this post https://github.com/microsoft/TypeScript/issues/15230#issuecomment-479730947 from @DaviSpindola and tried it. That was it

@vort3xxx I did not. I saw this post #15230 (comment) from @DaviSpindola and tried it. That was it

Same problem, same solution. TS 3.5.2.

@ThomasdenH

@simonbuchan I tried a .d.ts but that didn't work for me either, I will report back with why exactly, not sure what it was. And indeed CRA rewrote that setting for me.

Encountering the exact same issue. Did you ever figure out how to solve this? Defining .ts or .d.ts declaration files inside of a create react app returns the error All files must be modules when the '--isolatedModules flag is provided. Setting the flag to false or removing the isolatedModules property entirely resets to true when starting create react app.
Adding export {} at the bottom of the declaration file results in the error: Invalid module name in augmentation. Module '...' resolves to an untyped module at '...'.

Someone please help. How do I add custom declaration files to a create react app project?

Just figured it out if anyone else is having the same issue. Simply add your declaration types to the react-app-env.d.ts file in the source folder when using create react app.

Was this page helpful?
0 / 5 - 0 ratings