Understanding esModuleInterop: CommonJS vs ES Module in TypeScript
The article explains how toggling TypeScript's esModuleInterop flag changes import behavior between CommonJS and ES Module syntax, causing runtime errors like “TPS is not a constructor,” and offers fixes—either revert the flag and use namespace imports or enable it and use default imports.
Background: an unexpected issue caused by changing esModuleInterop from false to true, leading to a runtime error when uploading images.
Error: TypeError: TPS is not a constructor from code importing @ali/tps-node .
Fixes:
Set esModuleInterop back to false and adjust import syntax.
Change import to default: import TPS from '@ali/tps-node';
The article then explains the differences between CommonJS and ES Module specifications and how esModuleInterop influences TypeScript compilation.
CommonJS vs ES Module
In ES Module, a file foo.ts can export:
export const foo = 'foo';
class Foo {};
export default Foo;Importing:
import Foo from './foo'; // default export
import * as foo from './foo'; // all exports as object { foo: 'foo', default: Foo }When esModuleInterop=false , TypeScript compiles imports to CommonJS require calls without helpers.
import * as foo from 'abc' → const foo = require('abc');When esModuleInterop=true , TypeScript adds helper functions __importDefault and __importStar to emulate default exports.
import Foo from 'abc' → const Foo_1 = __importDefault(require('abc'));
import * as foo from 'abc' → const foo = __importStar(require('abc'));These helpers wrap CommonJS modules so that default import works even if the module does not export a default.
Best practice for importing CommonJS modules in TypeScript:
Use esModuleInterop=false and import * as XX from 'XX' .
Or enable esModuleInterop=true and use import XX from 'XX' .
DaTaobao Tech
Official account of DaTaobao Technology
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.