Support for import d from "cjs" form CommonJS modules with —esModuleInterop

TypeScript 2.7 updates CommonJS/AMD/UMD module emit to synthesize namespace records based on the presence of an __esModule indicator under —esModuleInterop.The change brings the generated output from TypeScript closer to that generated by Babel.

Previously CommonJS/AMD/UMD modules were treated in the same way as ES6 modules, resulting in a couple of problems. Namely:

  • TypeScript treats a namespace import (i.e. import * as foo from "foo") for a CommonJS/AMD/UMD module as equivalent to const foo = require("foo").Things are simple here, but they don’t work out if the primary object being imported is a primitive or a class or a function.ECMAScript spec stipulates that a namespace record is a plain object, and that a namespace import (foo in the example above) is not callable, though allowed by TypeScript

  • Similarly a default import (i.e. import d from "foo") for a CommonJS/AMD/UMD module as equivalent to const d = require("foo").default.Most of the CommonJS/AMD/UMD modules available today do not have a default export, making this import pattern practically unusable to import non-ES modules (i.e. CommonJS/AMD/UMD). For instance import fs from "fs" or import express from "express" are not allowed.

Under the new —esModuleInterop these two issues should be addressed:

  • A namespace import (i.e. import * as foo from "foo") is now correctly flagged as uncallabale. Calling it will result in an error.
  • Default imports to CommonJS/AMD/UMD are now allowed (e.g. import fs from "fs"), and should work as expected.

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();).

Example

With —esModuleInterop two new helpers are generated importStar and importDefault for import * and import default respectively.For instance input like:

  1. import * as foo from "foo";
  2. import b from "bar";

Will generate:

  1. "use strict";
  2. var __importStar = (this && this.__importStar) || function (mod) {
  3. if (mod && mod.__esModule) return mod;
  4. var result = {};
  5. if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
  6. result["default"] = mod;
  7. return result;
  8. }
  9. var __importDefault = (this && this.__importDefault) || function (mod) {
  10. return (mod && mod.__esModule) ? mod : { "default": mod };
  11. }
  12. exports.__esModule = true;
  13. var foo = __importStar(require("foo"));
  14. var bar_1 = __importDefault(require("bar"));