详解Typescript 内置的模块导入兼容方式


Posted in Javascript onMay 31, 2020

一、前言

前端的模块化规范包括 commonJS、AMD、CMD 和 ES6。其中 AMD 和 CMD 可以说是过渡期的产物,目前较为常见的是commonJS 和 ES6。在 TS 中这两种模块化方案的混用,往往会出现一些意想不到的问题。

二、import * as

考虑到兼容性,我们一般会将代码编译为 es5 标准,于是 tsconfig.json 会有以下配置:

{
 "compilerOptions": {
  "module": "commonjs",
  "target": "es5",
 }
}

代码编译后最终会以 commonJS 的形式输出。
使用 React 的时候,这种写法 import React from "react" 会收到一个莫名其妙的报错:

Module "react" has no default export

这时候你只能把代码改成这样:import * as React from "react"。
究其原因,React 是以 commonJS 的规范导出的,而 import React from "react" 这种写法会去找 React 模块中的 exports.default,而 React 并没有导出这个属性,于是就报了如上错误。而 import * as React 的写法会取 module.exports 中的值,这样使用起来就不会有任何问题。我们来看看 React 模块导出的代码到底是怎样的(精简过):

...
var React = {
 Children: {
  map: mapChildren,
  forEach: forEachChildren,
  count: countChildren,
  toArray: toArray,
  only: onlyChild
 },

 createRef: createRef,
 Component: Component,
 PureComponent: PureComponent,
 ...
}

module.exports = React;

可以看到,React 导出的是一个对象,自然也不会有 default 属性。

二、esModuleInterop

为了兼容这种这种情况,TS 提供了配置项 esModuleInterop 和 allowSyntheticDefaultImports,加上后就不会有报错了:

{
 "compilerOptions": {
  "module": "commonjs",
  "target": "es5",
  "allowSyntheticDefaultImports": true,
  "esModuleInterop": true
 }
}

其中 allowSyntheticDefaultImports 这个字段的作用只是在静态类型检查时,把 import 没有 exports.default 的报错忽略掉。
而 esModuleInterop 会真正的在编译的过程中生成兼容代码,使模块能正确的导入。还是开始的代码:

import React from "react";

现在 TS 编译后是这样的:

var __importDefault = (this && this.__importDefault) || function (mod) {
  return (mod && mod.__esModule) ? mod : { "default": mod };
};

Object.defineProperty(exports, "__esModule", { value: true });

var react_1 = __importDefault(require("react"));

编译器帮我们生成了一个新的对象,将模块赋值给它的 default 属性,运行时就不会报错了。

三、Tree Shaking

如果把 TS 按照 ES6 规范编译,就不需要加上 esModuleInterop,只需要 allowSyntheticDefaultImports,防止静态类型检查时报错。

{
 "compilerOptions": {
  "module": "es6",
  "target": "es6",
  "allowSyntheticDefaultImports": true
 }
}

什么情况下我们会考虑导出成 ES6 规范呢?多数情况是为了使用 webpack 的 tree shaking 特性,因为它只对 ES6 的代码生效。

顺便再发散一下,讲讲 babel-plugin-component。

import { Button, Select } from 'element-ui'

上面的代码经过编译后,是下面这样的:

var a = require('element-ui'); 
var Button = a.Button; 
var Select = a.Select;
var a = require('element-ui') 会引入整个组件库,即使只用了其中的 2 个组件。
babel-plugin-component 的作用是将代码做如下转换:

// 转换前
import { Button, Select } from 'element-ui'
// 转换后
import Button from 'element-ui/lib/button' 
import Select from 'element-ui/lib/select'

最终编译出来是这个样子,只会加载用到的组件:

var Button = require('element-ui/lib/button');
var Select = require('element-ui/lib/select');

四、总结

本文讲解了 TypeScript 是如何导入不同模块标准打包的代码的。无论你导入的是 commonJS 还是 ES6 的代码,万无一失的方式是把 esModuleInterop 和 allowSyntheticDefaultImports 都配置上。

到此这篇关于详解Typescript 内置的模块导入兼容方式的文章就介绍到这了,更多相关Typescript 内置模块导入兼容内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
传递参数的标准方法(jQuery.ajax)
Nov 19 Javascript
jQuery Lightbox 图片展示插件使用说明
Apr 25 Javascript
不用锚点也可以平滑滚动到页面的指定位置实现代码
May 08 Javascript
jquery animate实现鼠标放上去显示离开隐藏效果
Jul 21 Javascript
JS 日期比较大小的简单实例
Jan 13 Javascript
JS 在指定数组中随机取出N个不重复的数据
Jun 10 Javascript
jQuery实现设置、移除文本框默认值功能
Jan 13 Javascript
ztree获取选中节点时不能进入可视区域出现BUG如何解决
Dec 03 Javascript
WEB开发之注册页面验证码倒计时代码的实现
Dec 15 Javascript
微信JS SDK接入的几点注意事项(必看篇)
Jun 23 Javascript
微信小程序实现图片预览功能
Jan 31 Javascript
解决vue watch数据的方法被调用了两次的问题
Nov 07 Javascript
部署vue+Springboot前后端分离项目的步骤实现
May 31 #Javascript
JQuery获得内容和属性方法解析
May 30 #jQuery
JavaScript Window浏览器对象模型原理解析
May 30 #Javascript
基于canvasJS在PHP中制作动态图表
May 30 #Javascript
jQuery实现视频展示效果
May 30 #jQuery
vue实现购物车加减
May 30 #Javascript
基于vue和bootstrap实现简单留言板功能
May 30 #Javascript
You might like
Look And Say 序列php实现代码
2011/05/22 PHP
php从数据库中获取数据用ajax传送到前台的方法
2018/08/20 PHP
PHP实现获取ip地址的5种方法,以及插入用户登录日志操作示例
2019/02/28 PHP
jQuery 常见学习网站与参考书
2009/11/09 Javascript
jQuery中Ajax的load方法详解
2015/01/14 Javascript
JavaScript之数组(Array)详解
2015/04/01 Javascript
JavaScript中的anchor()方法使用详解
2015/06/08 Javascript
简介JavaScript中Math.LOG10E属性的使用
2015/06/14 Javascript
JS+CSS实现的简单折叠展开多级菜单效果
2015/09/12 Javascript
js简单时间比较的方法
2016/08/02 Javascript
Vue.js学习之计算属性
2017/01/22 Javascript
详解微信开发中snsapi_base和snsapi_userinfo及静默授权的实现
2017/03/11 Javascript
基于vue实现swipe分页组件实例
2017/05/25 Javascript
Ionic3 UI组件之Gallery Modal详解
2017/06/07 Javascript
Javascript中prototype与__proto__的关系详解
2018/03/11 Javascript
JS实现前端动态分页码代码实例
2020/06/02 Javascript
vue实现登录拦截
2020/06/29 Javascript
vue中的v-model原理,与组件自定义v-model详解
2020/08/04 Javascript
js实现弹幕飞机效果
2020/08/27 Javascript
使用webpack5从0到1搭建一个react项目的实现步骤
2020/12/16 Javascript
vue实现登录功能
2020/12/31 Vue.js
WebStorm无法正确识别Vue3组合式API的解决方案
2021/02/18 Vue.js
Python中使用gzip模块压缩文件的简单教程
2015/04/08 Python
分析python动态规划的递归、非递归实现
2018/03/04 Python
python的dataframe转换为多维矩阵的方法
2018/04/11 Python
详解Django的model查询操作与查询性能优化
2018/10/16 Python
Python图像处理之gif动态图的解析与合成操作详解
2018/12/30 Python
python整合ffmpeg实现视频文件的批量转换
2019/05/31 Python
关于Kotlin中SAM转换的那些事
2020/09/15 Python
Pop In A Box英国:Funko POP搪胶公仔
2019/05/27 全球购物
大学毕业生的自我鉴定
2013/11/30 职场文书
学生自我鉴定模板
2013/12/30 职场文书
歌唱比赛主持词
2014/03/18 职场文书
大学生考试作弊检讨书
2014/09/21 职场文书
2016春季幼儿园小班开学寄语
2015/12/03 职场文书
Python中异常处理用法
2021/11/27 Python