Image by Varsha Y S (Own work) [CC BY-SA 4.0 ()], via Wikimedia Commons
If you think you understand quantum mechanics, you don't understand quantum mechanics. ~ Probably Richard Feynman
We can say the same about ECMAScript Modules. If anything below does not seem quite right, please let me know @shaunluttin on Twitter.
Importing Modern Modules
Before we compare the
import = and
import * syntax, lets look at two ways to import modern ECMAScript modules.
import m from "module"
- Highly recommended.
- This is a default import.
- Use it to import a default export.
- It is more highly recommended than a destructed import is, because...
- default export is more highly recommended than named export is, and
- an ES6 Modules' design goal is "default exports are favored."
import { m } from "module"
- Recommended.
- This is a named/destructured import.
- Use it to import a named export.
Import of CommonJS/AMD Modules
Though the modern imports are part of ECMAScript 6 Modules' (ESM) specification, neither NodeJS nor major browsers support the ESM loader yet. NodeJS marks ESM as experimental and has a proposal to make ESM interoperate with its existing CommonJS module loader. Major browsers are starting to support ESM. That means we will eventually have ESM as a common module loader API for the server and the browser. In the meantime, we must use Babel or TypeScript to transpile ECMAScript Modules down to CommonJS, AMD, or some other module syntax. Importantly: the emerging ECMA Modules' loader needs to be compatible with the NodeJS/CommonJS module loader. That need for interop is why we have the following two (plus one) import styles:
import m = require("module")
- Recommended for importing CommonJS modules.
- The TypeScript Handbook says "When importing a module using
export =, TypeScript-specific
import module = require("module")must be used to import the module." (And TypeScript is just modern ECMAScript with types.)
import * as m from "module"
- Bad style. Bad interop. Avoid.
- Style: AirBnb says "Do not use use wildcard imports. Why? This encourages a single default export."
- Interop: There is a long conversation about CommonJS interop in this GitHub Issue. The TL;DR; is that ESM needs to remain compatible with CommonJS, and
import * as ...might emit non-callable namespace records, which would break both primitive exports (
export = 10) and function/constructor exports (
export = () => {});
const m = require("module")
- Legacy. Avoid. This breaks static analysis.
Conclusion
Use
import = only to consume legacy modules; avoid
import ... as entirely, and approach ECMAScript modules with intellectual humility.