270

In a create-react-app typescript project, I tried to write this just to test some stuff quickly:

// experiment.test.ts
it('experiment', () => {
  console.log('test');
});

But it gives me the following error, with a red squiggly beneath it:

All files must be modules when the '--isolatedModules' flag is provided.

However, if I change the file to the following, then everything apparently is fine (except for the unused import of course):

// experiment.test.ts
import { Component} from 'react'; // literally anything, don't even have to use it

it('test', () => {
  console.log('test');
});

Why? What is happening here? What does --isolatedModules actually mean/do?

3

9 Answers 9

462

Typescript treats files without import/exports as legacy script files. As such files are not modules and any definitions they have get merged in the global namespace. isolatedModules forbids such files.

Adding any import or export to a file makes it a module and the error disappears.

Also export {} is a handy way to make a file a module without importing anything.

5
  • 6
    If you don't want isolatedModules just set them to false. Commented Jul 2, 2020 at 10:30
  • 4
    It is like adding some rule and then ignoring it by adding @ts-ignore. The export {} is just a different syntax, way of bypassing the rule, but in principle is exactly that. Commented Jul 2, 2020 at 13:15
  • 8
    I don't see an issue with having general rules that are followed 99% of the time, but that sometimes needs to be broken. Having to "break a rule", as long as the rule generally is a good one, it forces me to think about what I'm doing and consider if there are better ways to solve something. And sometimes there isn't. Like in this case, where I was just making a test-file to try something out.
    – Svish
    Commented Jul 3, 2020 at 8:16
  • @Titian Cernicova-Dragomir, can whate are legacy script files? can you give any examples?
    – Karen
    Commented Oct 6, 2020 at 17:36
  • In my case I just had to give the exported variable the same name as the filename - and it was fixed! You may need to restart the dev server. Commented Jun 16, 2021 at 13:55
112

The correct way is to tell TypeScript what you want. If you don't want isolatedModules create tsconfig.json inside your test directory and add:

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "isolatedModules": false
  },
}

Adding "isolatedModules": true to the config and then cheating TypeScript checker by adding empty export {} smells bad code to me.

5
  • 2
    as explained in other comments, in this particular case, it won't be counted as code smell, it's a necessity over here, since there is no other way to partially exclude some file from the isolutedModules rule Commented Jul 3, 2020 at 12:42
  • Hmm, when I frob true to false, I am told in reply: TypeError: Cannot assign to read only property 'isolatedModules' of object '# <Object>' at verifyTypeScriptSetup Commented Oct 27, 2020 at 17:59
  • @JerryAsher same here man, but it worked earlier and then I reverted some code and tried to run it, which is when I got the exact same error. Commented Nov 4, 2020 at 8:58
  • 1
    This didn't work for me because I got this message: The following mandatory changes were made to your tsconfig.json: - isolatedModules was set to true (requirement for SWC / Babel) Commented Apr 14, 2022 at 21:29
  • Personally, I prefer the export {} because you can generally enforce isolatedModules, but explicitly show files that are the exception. Commented Mar 31, 2023 at 22:25
20

Still having error despite you exporting things from that "error file"?

  1. Check if you don't export same name that you already export in another file (conflict)
  2. After your fix try to stop and start your npm/yarn runner (I experienced it cannot recover itself even after hard reload of the page especially when you have another error somewhere else)
1
  • 1
    or in my case: 3. Make sure there's not an empty file with the same name which you were mistakenly checking
    – notracs
    Commented Mar 3, 2022 at 1:14
10

In case you don't want to add the unnecessary

export {}

everywhere and don't want to ruin the compiler option for other files.

If you have a separate tests/ directory, you can extend the root directory tsconfig file and create a new one in the tests/ directory.

Then add this to it:

{
    "extends": "../tsconfig.json",
    "compilerOptions": {
        "isolatedModules": false
    },
}

This turns off the isolatedModules flag only for test files. Restart your code-editor to sync the changes.

1
  • 4
    Good idea! Unfortunately I don't have a separate tests directory though, as it's much easier to stay organized when tests are co-located with the file they're testing.
    – Svish
    Commented Oct 14, 2022 at 11:53
3

Let's try to check isolated modules. When I checked Google, there is no direct context of it.

It basically means that you allow Typescript to compile modules in isolation.

But it comes from Typescript and has something to do with Typescript preferring modules over namespaces.

Modules also have a dependency on a module loader (such as CommonJs/Require.js) or a runtime which supports ES Modules. Modules provide for better code reuse, stronger isolation and better tooling support for bundling.

Source 1

Using a create-react-app typescript project, you should have installed typescript and ts-jest (or the create-react-app should handle the dependencies based on wether you ejected the app or not).

Also ts-jest has some information about it:

By default ts-jest uses TypeScript compiler in the context of a project (yours), with full type-checking and features. But it can also be used to compile each file separately, what TypeScript calls an ‘isolated module’. That’s what the isolatedModules option (which defaults to false) does.

Source 2

As soon as you use the export command you are creating a module out of what is being exported.

If you are using ts-jest, you can add these settings without affecting your other modules, which the create-react-app will consist off.

"ts-jest": {
  "isolatedModules": false
}

And checkout the ts-jest page (second source) for the pro's and con's.

1
  • 1
    Doing this in my jest.config.js resolved it -- ` 'ts-jest': { tsconfig: { isolatedModules: false }` however, if I just do an import from another file it also converts it to a module and then this is not necessary.
    – Clay
    Commented Nov 9, 2021 at 22:30
0

In my case adding export {}; was not enough.

I met this error in the webpack.config.ts file. The error message looked like this:

'webpack.config.ts' cannot be compiled under '--isolatedModules' because it is considered a global script file. Add an import, export, or an empty 'export {}' statement to make it a module.ts(1208)

When I added export {}; I got another error:

SyntaxError: Unexpected token ‘export' at Object.compileFunction (node:vm:352:18)…

I tried to change tsconfig.json module option from:

{
  "compilerOptions": {
    "module": "EsNext",
    "isolatedModules": true
  },

to:

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

,because webpack.config.ts had commonjs syntax like module.export ={}. Unfortunately, it didn't work too. I discovered that there were no type definitions added to the project, so I run:

npm install --save-dev ts-node @types/node @types/webpack

and everything was fine. The file was recognized as a module thanks to export {};.

Of course, using export {}; to make the file a module is just a workaround, not a solution. I could

  • change webpack.config file extension to .js instead of .ts and stay with the commonJS module format
  • change to import/export statements in ES modules format and use the .mjs file extension, because Node.js has stable support for ES modules since version 13.2.0 was introduced. Nevertheless, that would trigger other problems with changing commonJS syntax Can I use as es-modules for webpack config?
  • leave .ts file extension, follow the webpack configuration guide for typescript and use ES modules link

I chose the third option and had to add import 'webpack-dev-server'; to avoid type errors. My configuration changed from this:

export {};

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const webpack = require('webpack');

module.exports = (env) => {...}

to this:

import * as path from 'path';
import * as webpack from 'webpack';
import 'webpack-dev-server';
import HtmlWebpackPlugin from 'html-webpack-plugin';

const config = (env: { [x: string]: any; }): webpack.Configuration => {...}
export default config;
-2

That's because you haven't imported the function to be tested yet. Once you do that, the error will disappear. The accepted answer explains why.

-4

how about just do .eslintignore add the file folder where u need to ignore from eslint so no errors on that --isolatedModules error fixed by any imports and u can test your logics their

-4

Problem solving, see article https://blog.csdn.net/qingfeng812/article/details/120510673

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": false,
    "noEmit": true,
    "jsx": "react-jsx"
  },
  "include": [
    "src"
  ]
}
1
  • As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.
    – Community Bot
    Commented Sep 27, 2021 at 8:14

Not the answer you're looking for? Browse other questions tagged or ask your own question.