详解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 相关文章推荐
脚本收藏iframe
Jul 21 Javascript
JQuery Tips(3) 关于$()包装集内元素的改变
Dec 14 Javascript
基于jQuery的实现简单的分页控件
Oct 10 Javascript
jQuery学习笔记之jQuery.fn.init()的参数分析
Jun 09 Javascript
浅谈javascript中onbeforeunload与onunload事件
Dec 10 Javascript
基于javascript实现简单的抽奖系统
Apr 15 Javascript
AngularJS入门教程之AngularJS表达式
Apr 18 Javascript
详解es6超好用的语法糖Decorator
Aug 01 Javascript
浅析Angular 实现一个repeat指令的方法
Jul 21 Javascript
vue.js实现二级菜单效果
Oct 19 Javascript
JS面向对象之多选框实现
Jan 17 Javascript
vue.js+element 默认提示中英文操作
Nov 11 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
php格式化日期和时间格式化示例分享
2014/02/24 PHP
浅析Yii2中GridView常见操作
2016/04/22 PHP
thinkphp5.0自定义验证规则使用方法
2017/11/16 PHP
javascript 页面只自动刷新一次
2009/07/10 Javascript
img标签中onerror用法
2009/08/13 Javascript
JS 判断undefined的实现代码
2009/11/26 Javascript
javascript getElementsByClassName 和js取地址栏参数
2010/01/02 Javascript
jQuery Dialog 弹出层对话框插件
2010/08/09 Javascript
从jquery的过滤器.filter()方法想到的
2013/09/29 Javascript
jquery fancybox ie6不显示关闭按钮的解决办法
2013/12/25 Javascript
关于onchange事件在IE和FF下的表现及解决方法
2014/03/08 Javascript
jQuery学习笔记之jQuery+CSS3的浏览器兼容性
2015/01/19 Javascript
JQuery实现列表中复选框全选反选功能封装(推荐)
2016/11/24 Javascript
原生js更改css样式的两种方式
2017/03/15 Javascript
写给vue新手们的vue渲染页面教程
2017/09/01 Javascript
vue组件watch属性实例讲解
2017/11/07 Javascript
微信小程序如何实现radio单选框单击打勾和取消
2020/01/21 Javascript
vue实现购物车案例
2020/05/30 Javascript
mapboxgl实现带箭头轨迹线的代码
2021/01/04 Javascript
[49:43]VG vs FNATIC 2019国际邀请赛小组赛 BO2 第一场 8.15
2019/08/17 DOTA
Python语言编写电脑时间自动同步小工具
2013/03/08 Python
Python 3.x读写csv文件中数字的方法示例
2017/08/29 Python
Python单向链表和双向链表原理与用法实例详解
2018/08/31 Python
python银行系统实现源码
2019/10/25 Python
python实现翻译word表格小程序
2020/02/27 Python
tensorflow常用函数API介绍
2020/04/19 Python
高街生活方式全球在线商店:AZBRO
2017/08/26 全球购物
Python使用openpyxl复制整张sheet
2021/03/24 Python
毕业生教师求职信
2013/10/20 职场文书
机械专业毕业生自荐信
2013/11/02 职场文书
信息专业个人的自我评价
2013/12/27 职场文书
导游的职业规划书范文
2013/12/27 职场文书
优秀党员主要事迹
2014/01/19 职场文书
事务机电主管工作职责
2014/02/25 职场文书
求职信内容一般写什么?
2015/03/20 职场文书
关于办理居住证的介绍信模板
2019/11/27 职场文书