详解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 相关文章推荐
js特殊字符过滤的示例代码
Mar 05 Javascript
js判断上传文件类型判断FileUpload文件类型代码
May 20 Javascript
jquery列表拖动排列(由项目提取相当好用)
Jun 17 Javascript
JS日期格式化之javascript Date format
Oct 01 Javascript
基于JS代码实现实时显示系统时间
Jun 16 Javascript
浅述节点的创建及常见功能的实现
Dec 15 Javascript
JS常见创建类的方法小结【工厂方式,构造器方式,原型方式,联合方式等】
Apr 01 Javascript
详解vue跨组件通信的几种方法
Jun 15 Javascript
在 vue-cli v3.0 中使用 SCSS/SASS的方法
Jun 14 Javascript
关于vue表单提交防双/多击的例子
Oct 31 Javascript
Vue在chrome44偶现点击子元素事件无法冒泡的解决方法
Dec 15 Javascript
利用Vue实现简易播放器的完整代码
Dec 30 Vue.js
部署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
php实现模拟登陆方正教务系统抓取课表
2015/05/19 PHP
解决thinkPHP 5 nginx 部署时,只跳转首页的问题
2019/10/16 PHP
Javascript代码混淆综合解决方案-Javascript在线混淆器
2006/12/18 Javascript
JavaScript 版本自动生成文章摘要
2008/07/23 Javascript
二级域名或跨域共享Cookies的实现方法
2008/08/07 Javascript
Jquery 的扩展方法总结
2011/10/01 Javascript
教你用jquery实现iframe自适应高度
2014/06/11 Javascript
js控制网页背景音乐播放与停止的方法
2015/02/06 Javascript
jQuery实现form表单元素序列化为json对象的方法
2015/12/09 Javascript
JavaScript自动点击链接 防止绕过浏览器访问的方法
2017/01/19 Javascript
React-Native做一个文本输入框组件的实现代码
2017/08/10 Javascript
详解Jest结合Vue-test-utils使用的初步实践
2019/06/27 Javascript
JavaScript this在函数中的指向及实例详解
2019/10/14 Javascript
微信小程序webSocket的使用方法
2020/02/20 Javascript
Element Rate 评分的使用方法
2020/07/27 Javascript
[01:10:24]DOTA2-DPC中国联赛 正赛 VG vs Aster BO3 第一场 2月28日
2021/03/11 DOTA
python通过colorama模块在控制台输出彩色文字的方法
2015/03/19 Python
Python 列表排序方法reverse、sort、sorted详解
2016/01/22 Python
浅谈python 四种数值类型(int,long,float,complex)
2016/06/08 Python
python批量查询、汉字去重处理CSV文件
2018/05/31 Python
Python wxPython库Core组件BoxSizer用法示例
2018/09/03 Python
Python3.5常见内置方法参数用法实例详解
2019/04/29 Python
python删除列表元素的三种方法(remove,pop,del)
2019/07/22 Python
超级英雄、电影和电视、乐队和音乐T恤:Loud Clothing
2019/09/01 全球购物
美国和加拿大计算机和电子产品购物网站:TigerDirect.com
2019/09/13 全球购物
灵泰克Java笔试题
2016/01/09 面试题
影视艺术学院毕业生自荐信
2013/11/13 职场文书
幼儿园家长会欢迎词
2014/01/09 职场文书
学校岗位设置方案
2014/01/16 职场文书
学生自我评价范文
2014/02/02 职场文书
大专生自我鉴定怎么写
2014/09/16 职场文书
2015年秋季小班开学寄语
2015/05/27 职场文书
无婚姻登记记录证明
2015/06/18 职场文书
2015暑假打工实践报告
2015/07/13 职场文书
2015暑期社会实践调查报告
2015/07/14 职场文书
Python 第三方库 openpyxl 的安装过程
2022/12/24 Python