DEV Community

loading...

Understand "esModuleInterop" option in Typescript

tmhao2005 profile image tmhao2005 ・2 min read

Here are couple of cases that I have tested how the option esModuleInterop of Typescript compiler (tsc) works.

Each test will have 2 different imports (one is default import and an namespace import) and we'll check the generated code.

#1

  • { esModuleInterop: false } with tsc
import * as foo from "foo";
import bar from "bar";

console.log(foo, bar)

// JS

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var foo = require("foo");
var bar = require("bar");
// I'm not sure why (`.default`), but most of `commonjs` modules 
// won't export this value which causes void 0
console.log(foo, bar.default);

Enter fullscreen mode Exit fullscreen mode

#2

  • { esModuleInterop: true } with tsc:
import * as foo from "foo";
import bar from "bar";

console.log(foo, bar)

// JS
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};

Object.defineProperty(exports, "__esModule", { value: true });
var foo = __importStar(require("foo"));
var bar = __importDefault(require("bar"));

// In this case, `foo` won't work if `foo` is `commonjs` which is a single export: 
// `module.exports = {}` 
// then it would return { default: {} }
console.log(foo, bar.default);
Enter fullscreen mode Exit fullscreen mode

Finally, we have an issue with webpack:

Let's say to have module foo which is quite common pattern:

- lib
-- index.cjs.js
-- index.esm.js
Enter fullscreen mode Exit fullscreen mode

index.cjs.js

module.exports = {}
Enter fullscreen mode Exit fullscreen mode

index.esm.js

export default {}
Enter fullscreen mode Exit fullscreen mode

Then import:

import * as foo from "foo"

console.log(foo)
Enter fullscreen mode Exit fullscreen mode

with foo's package.json:

{
  main: './lib/index.cjs.js',
  module: './lib/index.esm.js'
}
Enter fullscreen mode Exit fullscreen mode

would result in in webpack:

var foo = __webpack_require__("./node_modules/foo/lib/index.esm.js");

console.log(foo) // { default: {...} }

// But with `cjs`, it works

var foo = __webpack_require__("./node_modules/foo/lib/index.cjs.js");

console.log(foo) // {...}

Enter fullscreen mode Exit fullscreen mode

If webpack takes es2015+ module, it will transform to harmony module.

/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! react */ "react");
/* harmony default export */ __webpack_exports__["default"] = (Bar);
Enter fullscreen mode Exit fullscreen mode
  • __webpack_require__ with esm:
// foo.js
export default 1;

// result
__webpack_require__('foo.js'); // { default: 1 }
Enter fullscreen mode Exit fullscreen mode
  • __webpack_require__ with cjs:
// foo.js
module.exports = 1;

// result
__webpack_require__('foo.js'); // 1
Enter fullscreen mode Exit fullscreen mode
  • esModuleInterop option won't affect to es2015+ module.

Discussion (0)

pic
Editor guide