详解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 相关文章推荐
javaScript 简单验证代码(用户名,密码,邮箱)
Sep 28 Javascript
JS获取节点的兄弟,父级,子级元素的方法
Jan 09 Javascript
用IE重起计算机或者关机的示例代码
Mar 10 Javascript
jQuery向后台传入json格式数据的方法
Feb 13 Javascript
简单对比分析JavaScript中的apply,call与this的使用
Dec 04 Javascript
在页面中输出当前客户端时间javascript实例代码
Mar 02 Javascript
javascript经典特效分享 手风琴、轮播图、图片滑动
Sep 14 Javascript
Angular6笔记之封装http的示例代码
Jul 27 Javascript
解决百度Echarts图表坐标轴越界的方法
Oct 17 Javascript
详解Vue组件插槽的使用以及调用组件内的方法
Nov 13 Javascript
微信小程序基于movable-view实现滑动删除效果
Jan 08 Javascript
详解Vite的新体验
Feb 22 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
ThinkPHP CURD方法之data方法详解
2014/06/18 PHP
php实现把url转换迅雷thunder资源下载地址的方法
2014/11/07 PHP
php压缩和解压缩字符串的方法
2015/03/14 PHP
Yii2中SqlDataProvider用法示例
2016/09/22 PHP
一起来写段JS drag拖动代码
2010/12/09 Javascript
Three.js源码阅读笔记(光照部分)
2012/12/27 Javascript
javascript获取ckeditor编辑器的值(实现代码)
2013/11/18 Javascript
jQuery动态改变图片显示大小(修改版)的实现思路及代码
2013/12/24 Javascript
JS 操作Array数组的方法及属性实例解析
2014/01/08 Javascript
JS常用函数使用指南
2014/11/23 Javascript
使表格的标题列可左右拉伸jquery插件封装
2014/11/24 Javascript
JavaScript中的call方法和apply方法使用对比
2015/08/12 Javascript
javascript编程异常处理实例小结
2015/11/30 Javascript
JavaScript表单验证实例之验证表单项是否为空
2016/01/10 Javascript
jQuery实现鼠标跟随提示层效果代码(可显示文本,Div,Table,Html等)
2016/04/18 Javascript
ionic2 tabs使用 Modal底部tab弹出框
2016/12/30 Javascript
详解vue-cil和webpack中本地静态图片的路径问题解决方案
2017/09/27 Javascript
Vue组件的使用教程详解
2018/01/05 Javascript
vue基于element-ui的三级CheckBox复选框功能的实现代码
2018/10/15 Javascript
三分钟教你用Node做一个微信哄女友(基友)神器(面向小白)
2019/06/21 Javascript
nodejs和react实现即时通讯简易聊天室功能
2019/08/21 NodeJs
Python首次安装后运行报错(0xc000007b)的解决方法
2016/10/18 Python
python实现的config文件读写功能示例
2019/09/24 Python
解决django-xadmin列表页filter关联对象搜索问题
2019/11/15 Python
Python3批量创建Crowd用户并分配组
2020/05/20 Python
使用python编写一个语音朗读闹钟功能的示例代码
2020/07/14 Python
浅谈Selenium+Webdriver 常用的元素定位方式
2021/01/13 Python
基于CSS3实现的几个小loading效果
2018/09/27 HTML / CSS
HTML5中实现拖放效果无须借助javascript
2012/12/26 HTML / CSS
造价工程师个人求职信
2013/09/21 职场文书
日本语毕业生自荐信
2014/02/01 职场文书
管理失职检讨书
2014/02/12 职场文书
入股协议书
2014/04/14 职场文书
新人入职感言
2015/07/31 职场文书
JavaScript组合继承详解
2021/11/07 Javascript
Django框架中模型的用法
2022/06/10 Python