79

With TypeScript 2.7.2, in VSCode version 1.21 with @types/express and the code that follows, in some cases VSCode throws errors stating that

A namespace-style import cannot be called or constructed, and will cause a failure at runtime.

However on other machines with similar setups and similar tsconfig.json files the code just works. What is happening here...

import { Bank } from './Bank';
import * as Express from 'express';  <== errors here..

let app: Express.Express;
this.app = Express();                <== and here

Why is this happening?

TIA,

John.

mikemaccana
  • 110,530
  • 99
  • 389
  • 494
John Gorter
  • 2,162
  • 2
  • 17
  • 25

3 Answers3

168

The error should only happen with esModuleInterop: true. Maybe VSCode is ignoring your tsconfig.json or another one with esModuleInterop: true is used.

For a definitive fix set the compiler option esModuleInterop to true and use import express instead of import * as express.

The problem :

The ES6 specification defines the notion of "namespace object". A namespace object is namespaceObject in this statement : import * as namespaceObject from 'a-module'. The typeof this object is object, you are not supposed to be able to call it.

You were using import * as express until now because express is a CommonJS module, for Node.js, it is exported using module.exports. However it is illegal in the ES6 spec, and TypeScript now warns you.

The solution :

Setting esModuleInterop to true will make TypeScript wrap your import calls to check if the module is an ES6 module or a CommonJS. If it's a CommonJS module and you are using import default from 'module' TypeScript will find out and return the correct CommonJS module.

From the TypeScript release note :

Note: The new behavior is added under a flag to avoid unwarranted breaks to existing code bases. We highly recommend applying it both to new and existing projects. For existing projects, namespace imports (import * as express from "express"; express();) will need to be converted to default imports (import express from "express"; express();).

Fathy
  • 4,939
  • 1
  • 23
  • 25
  • 11
    The line that helped me the most from the linked release notes was "Under the new --esModuleInterop flag, these callable CommonJS modules must be imported as default imports...", with an example of `import express from "express"`. This of course fails if `allowSyntheticDefaultImports` isn't `true`, which basically means that flag is required to consume callable modules. – Coderer Sep 17 '18 at 11:29
  • 1
    Thanks for this. I've been getting these kinds of errors when using `momentjs` and your answer is exactly what I needed. – Mark Birbeck May 26 '20 at 16:47
  • 1
    Helped me solve issues with momentjs as well, I used import this way: `import moment, { Moment } from 'moment';` – Patronaut May 11 '21 at 17:51
  • Yes, thank you! MomentJs was causing this issue for me as well. – Willie Sep 15 '21 at 16:46
  • 1
    Somehow I'm still getting this error with both of the below `"esModuleInterop": true, "allowSyntheticDefaultImports": true` any ideas? – Chima - UserAndI Oct 05 '21 at 09:20
  • 2
    @Chima Did you find any solution? It failed for me too even after enabling both together? – Rohit Mittal Oct 14 '21 at 11:25
  • 2
    @RohitMittal i didn't unfortunately - i just left it as require – Chima - UserAndI Oct 20 '21 at 23:27
  • 1
    @RohitMittal I had the same issue and I think I have a solution (that still uses ES6 modules) - see my answer. – mikemaccana Nov 18 '21 at 16:45
18

In my case I already had "esModuleInterop": true enabled in tsconfig.json. I needed to convert:

import * as assert from "assert";

to:

import assert from "assert";

mikemaccana
  • 110,530
  • 99
  • 389
  • 494
  • 1
    After doing the suggestion in the selected answer, it did not work for me still... However, this change, worked! – Gel Apr 06 '22 at 12:43
4

How about this:

import express = require('express');
yohanes
  • 2,365
  • 1
  • 15
  • 24
  • It is not weird. TypeScript supports this: https://www.typescriptlang.org/docs/handbook/modules.html#export--and-import--require – Andrei Drynov May 26 '22 at 08:52