133

I'm trying to make a simple API using typescript and NodeJS but when I run my code I get this error

"This module is declared with using 'export =', and can only be used with a default import when using the 'esModuleInterop' flag."

This is my code: package.json

    {
  "name": "API-Proyecto",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "cors": "^2.8.5",
    "express": "^4.17.1",
    "jsonwebtoken": "^8.5.1"
  },
  "devDependencies": {
    "@types/cors": "^2.8.6",
    "@types/express": "^4.17.6",
    "nodemon": "^2.0.4"
  }
}

Index.ts

    import express from 'express';
import { Request, Response }  from 'express';
import cors from 'cors';

const app = express();

app.use(express.urlencoded({extended: true}));
app.use(express.json);
app.use(cors({origin: true, credentials: true}));

app.get('/api/auth/testing', (req: Request, res: Response) =>{
    res.status(200).json({
        ok : true,
        msg : 'hi from my method'
    });
});

app.listen(3000, () => {console.log('Server running on 3000' )});

tsconfig.json

    {
  "compilerOptions": {
    "target": "es6",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
    "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
    "outDir": "./dist",                        /* Redirect output structure to the directory. */
    "esModuleInterop": true,                  /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
  }
}
5
  • 3
    Your code is fine. If you are curious on this flag I've created a lesson on it: youtube.com/watch?v=bx4AjADk6eQ
    – basarat
    Commented Jun 9, 2020 at 5:28
  • Thank you so much! I don't have an idea about the error but your lesson is helpful to learn more Commented Jun 9, 2020 at 15:44
  • 5
    In my case the "esModuleInterop": true was missing Commented Oct 15, 2021 at 21:21
  • 1
    I had a similar problem, but I forgot to create de tsconfig.json file. once i generated it, the issue was fixed
    – innis
    Commented Jan 22, 2022 at 1:03
  • This one is missing Interop Constraints Commented Jun 29, 2022 at 12:22

17 Answers 17

189

Your code is perfectly fine.

Fix

When you make changes to tsconfig, sometimes you need to restart your IDE or Code Editor 🌹

1
  • 29
    If you are using VSCode, you can run TypeScript: Reload Project from the command pallet.
    – Sean256
    Commented Jul 29, 2021 at 19:22
120

Use:

import * as express from 'express';
3
  • 1
    I had a similar issue for momentjs in VSCode and your approach resolved my case.
    – Utku A.
    Commented Dec 20, 2021 at 18:43
  • 3
    This raised a tsserver error on express(): This expression is not callable. Type 'typeof e' has no call signatures. (tsserver 2349)
    – manuch100
    Commented Jun 20, 2023 at 9:46
  • Maybe you're using a version of the express package that doesn't return a function by default, so I recommend either looking in the documentation or trying to find it in their project implementation or doing a debug to see everything that is exported by express, because there may be some version that needs to call a function inside the object, which would be something like express.function(). Commented Jun 21, 2023 at 14:25
38

My problem was that I tried to run tsc as tsc -w index.ts.

However, as said here https://stackoverflow.com/a/33244030/5711655 if you run tsc with a specified input file, it won't use the tsconfig.json in your project directory! So in my case I had to use tsc -w.

1
  • 3
    That is so annoying that tsc ignores tsconfig.json when called with a specific file argument.
    – hlovdal
    Commented Apr 25, 2023 at 12:25
23

I fixed similar mistake for yourself. I use project (vite + vue 3 + ts)

  1. added on tsconfig.json->compilerOptions + "moduleResolution": "node".
  2. import moment from "moment" to import * as moment from "moment";

UPD:- and add this setting,

"allowSyntheticDefaultImports": true

and then I can use, import moment from "moment";

1
  • 2
    import * as somelibrary from "somelibrary" worked for me thanks. Commented Aug 21, 2022 at 19:42
23

I was able to solve it by setting the "esModuleInterop" property to true inside the "compilerOptions" object in the tsconfig.json file.

{
  "compilerOptions": {
    "esModuleInterop": true,
    ...
  },
}

2
  • helped in my case as well
    – Alex Kogan
    Commented Jun 19, 2023 at 22:23
  • this one helped! ❤️ Commented May 16 at 6:28
8

Don't forget to set "moduleResolution": "node" in the tsconfig.json if you are using node.

8

When working with Typescript you you need to add a flag on your tsconfig.json file that allows synthetic Imports as so:

  • open tsconfig.json
  • add:
{
  "compilerOptions": {
    "jsx": "react",
    "module": "es6",
    "target": "es6",
    "moduleResolution": "node", 
    "allowSyntheticDefaultImports": true
  }
}
5

I solved the problem by compiling the whole file instead of compiling individual files.

Just run the following command to compile the whole file in a go

npx tsc

This should solve your problem

3
  • It works for me with conjunction with this answer: stackoverflow.com/a/74788007/7883681
    – Tayan
    Commented May 10, 2023 at 23:21
  • Any idea why this is?
    – dwjohnston
    Commented Feb 20 at 0:24
  • After trying all the above solutions, this helped me.
    – bghad1
    Commented May 12 at 20:57
4

As with most answers here, I have tested a wide variety of settings in the tsconfig.json file and none have resolved my issue.

Response: In the end, I needed to change the way I am importing the express module:

server.ts:

import express = require('express'); //! import express from 'express';
import { Express, Request, Response } from 'express';

const SERVER_PORT: number = 3000;

const app: Express = express();

app.use(express.json());

app.get("/", (request: Request, response: Response) => {
    return response.json({ message: "Hello world!!!" });
});

app.listen(SERVER_PORT, () => {
    console.log(`Server running at: http://localhost:${SERVER_PORT}`);
});

And tsconfig.json:

{
  "compilerOptions": {
    "target": "ES2020",
    "module": "commonjs",
    "types": ["node", "express"],
    "lib": [
            "ES2020",
            "DOM",
        ],
    "allowJs": true,
    "sourceMap": true,
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "noImplicitAny": true,
    "noImplicitReturns": true,
    "moduleResolution": "node",
    "esModuleInterop": true,
    "resolveJsonModule": true
  }
}
2

You should set:

esModuleInterop in your ts.config.json to TRUE.

{
  "compilerOptions": {
    "lib": ["es5", "es6"],
    "target": "es5",
    "module": "commonjs",
    "moduleResolution": "node",
    "outDir": "./build",
    "emitDecoratorMetadata": true,
    "experimentalDecorators": true,
    "sourceMap": true,
    "esModuleInterop": true
  }
}
2
1

FWIW, I found that switching from

import * as blah from 'blah-lib';

To

const blah = require('blah-lib');

Fixed the issue at compile time.

1
  • 3
    this is not a solution since he wants to use esModules style Commented Jun 6, 2022 at 19:19
1

Just like @basarat said rightfully, restarting Typescript can fix this issue. I already included "esModuleInterop": true, in tsconfig.json. I want to add, that you can do this via the Intellij Footer as well. Click on your Typescript version there.

Thanks for the help.

Intellij Footer

0

I was wondering a lot but a friend helped me:

  1. You need to create a command inside of "scripts" part on package.json

Package.json

{
  "name": "api-proyecto",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    **"build-dev": "tsc -w"**
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@types/cors": "^2.8.6",
    "@types/express": "^4.17.6"
  },
  "dependencies": {
    "cors": "^2.8.5",
    "express": "^4.17.1"
  }
}
  1. To run your script you need to type the following line

    npm i run build-dev (because it's the name of our command)

  2. Finally in another powershell launch node normally. For Example:

    node .\dist\index.js

0

After trying all of the above solutions to no avail, I stumbled upon a solution for my case. I don't know why this works but running tsc instead of tsc index.ts or tsc --watch index.ts compiled fine. This error makes no sense to me at all. If someone can enlighten me and other readers of this post, it would be greatly appreciated.

1
0

I tried everything on this thread and it didn't work. What finally did was swapping tsc for ts-node to compile typescript in the app.

For reference I had this problem in a rushjs monorepo which may have further confused tsc

0

I had the same issue with my vscode, the error keeps on popping even with changing the tsconfig.json.

The problem was that tsconfig.json was extending from expo/tsconfig.base and somehow vscode didn't detect it.

{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "src/*": ["src/*"],
      "static/*": ["static/*"]
    }
  },
  "extends": "expo/tsconfig.base"
}

I just opened this expo/tsconfig.base with right click and then save it to make vscode aware of this.

0

Try to write:

import express = require('express');

It should work.

New contributor
ElPanissueloBarrios is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.

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