Skip to content

esModuleinterop

typescript中的esModuleInterop选项


当没有加esModuleInterop时

库的代码:

ts
export const a = 1
export default function b() {}

生成代码

js
exports.__esModule = true
exports.a = 1
function b() { }
exports.default = b

使用库的代码:

ts
import * as lib from './export'

console.log(lib)

生成代码

js
exports.__esModule = true
const lib = require('./export')
console.log(lib)
ts
import lib from './export'

console.log(lib)

生成代码

js
exports.__esModule = true
const export_1 = require('./export')
console.log(export_1.default)

以上代码使用ts生成代码都是可以的。但是如果我们使用的库是第三方的,比如fs。我们的代码如下

ts
import fs from 'node:fs'

console.log(fs)

生成代码

js
exports.__esModule = true

const fs_1 = require('node:fs')
console.log(fs_1.default)

fs是没有default属性的,所以这种使用fs的方法是不对的。

所以,不加esModuleInterop时,正确引用fs的方法是下面这样:

ts
import * as fs from 'node:fs'

// 或者

import { fsync } from 'node:fs'
console.log(fs)
console.log(fsync)

加上esModuleInterop,代码

ts
import * as lib from './export'

console.log(lib)

编译为:

js
const __importStar = (this && this.__importStar) || function (mod) {
  if (mod && mod.__esModule)
    return mod
  const result = {}
  if (mod != null) {
    for (const k in mod) {
      if (Object.hasOwnProperty.call(mod, k))
        result[k] = mod[k]
    }
  }
  result.default = mod
  return result
}
exports.__esModule = true
const lib = __importStar(require('./export'))
console.log(lib)

代码

ts
import lib from './export'

console.log(lib)

编译为

js
const __importDefault = (this && this.__importDefault) || function (mod) {
  return (mod && mod.__esModule) ? mod : { default: mod }
}
exports.__esModule = true
const export_1 = __importDefault(require('./export'))
console.log(export_1.default)

这时

ts
import fs from 'node:fs'

console.log(fs)

就可以正常使用了。

总结:

因为很多老的js库使用了commonjs的导出方式,并且没有导出default属性,而是使用module.exports=xxx直接导出,这样会导致 import fs from 'fs';的语法引入失败。

typescript为了兼容这些js库,于是引入了esModuleInterop,使import fs from 'fs'能正常使用。