Migrate CommonJS dependencies
A TypeScript application imports CommonJS packages and emits JavaScript with tsc.
TypeScript · Const
Enables more accurate interoperability between ES-style imports and CommonJS, AMD, or UMD modules. It changes checking and emitted helpers so default imports work as expected and namespace imports remain valid module objects.
esModuleInterop changes both checking and CommonJS-oriented emit so default imports work with CommonJS, AMD, and UMD modules, while namespace imports follow the ES module rule that their value must be an object. Enabling it also turns on allowSyntheticDefaultImports for type compatibility.
{
"compilerOptions": {
"esModuleInterop": true
}
}| Name | Type | Description |
|---|---|---|
esModuleInterop | boolean | Boolean compiler option; when true, adjusts module checking and emitted JavaScript for CommonJS, AMD, and UMD interoperability. |
allowSyntheticDefaultImports, improving type compatibility for default imports.verbatimModuleSyntax rather than turning this option off.import path from "node:path";
console.log(path.basename("/tmp/report.txt"));With CommonJS-compatible interop enabled, a default import can consume Node’s CommonJS-style module exports and run after compilation.
A TypeScript application imports CommonJS packages and emits JavaScript with tsc.
A project is type-checked by TypeScript but emitted by a bundler or transpiler with Babel-like interop.
A codebase wants default-import syntax for CommonJS or UMD packages.
esModuleInterop solve?It makes TypeScript’s module checking and emitted CommonJS interop agree with the behavior used by established transpilers and bundlers. It also fixes callable namespace imports and supports default-import syntax for CommonJS-style modules.
Follow-up: What happens to allowSyntheticDefaultImports? Enabling esModuleInterop enables it automatically, affecting type compatibility even where emit is handled elsewhere.
Without the option, TypeScript historically modeled a namespace import like a direct require result and modeled a default import like its .default property. Those assumptions are not generally compatible with CommonJS module shapes.
Follow-up: Why can’t a namespace import be callable under the ES module rules? A namespace import must produce an object-like module namespace, so callable CommonJS exports need a different import form.
For applications that use TypeScript to emit JavaScript, enabling or disabling it generally does not change whether error-free code runs, because checking and emit remain aligned in either mode. It matters more when a third-party bundler or transpiler emits the application, because those tools commonly use equivalent interop behavior.
Follow-up: What should a library author consider? verbatimModuleSyntax can make the module form explicit and avoid ambiguity for consumers with different interop settings.
allowSyntheticDefaultImportsverbatimModuleSyntaximport * asdefault importCommonJSAMDUMD