ES Module,commonjs,Typescript模块系统的关系

首先es和cmj大家都知道不一样,具体区别也就不多说,需要注意的是TS的模块也是自己实现的,不过在ES Module 2015(es6)定稿下来后,TS沿用和支持了ES module,不过TS除了使用ES module的规范,自己也有一套namespace的模块管理,这在某个版本前一直用namespace管理模块,直到后来和ESM保持一致才有改动。例如下面官网说法:

TypeScript 1.5里术语名已经发生了变化。 “内部模块”现在称做“命名空间”。 “外部模块”现在则简称为“模块”,这是为了与 ECMAScript 2015里的术语保持一致,(也就是说 module X { 相当于现在推荐的写法 namespace X {)。

注意babel是典型的ES module写法,babel本身就是将ES6,ES7的高级语法转为浏览器能读取的代码,babel项目迁移到ts,才会出现一些模块写法不兼容的问题。(react+ts项目中代码的转义是靠webpack的babel-loader来转义tsx,ts语法,babel-loader真强大,TS语法,类型的提示和校验则是靠ForkTsCheckerWebpackPlugin,TsconfigPathsPlugin,eslint等插件去完成)

TS中常常用import * as React 导入。

TS 把 CJS 模块作为一个 Namespace 导入,所以,为了解决上面提到的报错,需要这样导入 CJS 模块,以及任何没有 default 导出的模块: import * as React from 'react'

这样子的代码,如果从 babel 迁移到 TS 就需要大幅的改动代码,不过 TS 也注意到了这个问题,添加了一个 compile option 支持 babel 的这种写法 esModuleInterop, PR 在下面 https://github.com/Microsoft/TypeScript/pull/19675

// tsconfig.json
{
"esModuleInterop": true
}

在该选项中,所有 ES Module 文件会导出一个名为 __esModule 的隐藏属性,值为 true。对于导入 ES Module 时,所有行为没有变化。

整体导入其它模块(import * as ns)时,若不是 ES Module,则将导出内容本身作为模块的 default 属性,并将其它所有属性原样拷贝到模块中。

// module.js
module.exports = () => {
  console.log('foo')
}
exports.xixi = 'xixi'

// 使用
import * obj from 'module.js';

即module.export导出的模块,和其他挂载在exports上的属性,都会拷贝到* as obj的obj这个对象寄来,且执行obj.foo === 'foo' 为true,obj.default()则为打印foo,此时和es module的import 就表现一致了,导入的模块对象中default key为es module中default导出的或者cmj module.export导出的,其他属性则为es module 正常export的和cmj中挂载在exports的属性。

猜你喜欢

转载自www.cnblogs.com/zhangmingzhao/p/11995379.html