详解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----文件操作
Jan 18 Javascript
jquery 层次选择器siblings与nextAll的区别介绍
Aug 02 Javascript
JavaScript中toString()方法的使用详解
Jun 05 Javascript
js实现带农历和八字等信息的日历特效
May 16 Javascript
把json格式的字符串转换成javascript对象或数组的方法总结
Nov 03 Javascript
关于Node.js的events.EventEmitter用法介绍
Apr 01 Javascript
Vue异步组件使用详解
Apr 08 Javascript
Javascript实现一个简单的输入关键字添加标签效果实例
Jun 01 Javascript
JS与jQuery实现ListBox上移,下移,左移,右移操作功能示例
May 31 jQuery
详解Axios统一错误处理与后置
Sep 26 Javascript
关于Layui Table隐藏列问题
Sep 16 Javascript
js闭包和垃圾回收机制示例详解
Mar 01 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/09/23 PHP
删除PHP数组中的重复元素的实现代码
2017/04/10 PHP
Javascript 二维数组
2009/11/26 Javascript
使用js获取地址栏中传递的值
2013/07/02 Javascript
jquery交替变换颜色的三种方法 实例代码
2013/11/19 Javascript
JS判断指定dom元素是否在屏幕内的方法实例
2017/01/23 Javascript
浅谈webpack4.x 入门(一篇足矣)
2018/09/05 Javascript
vue实现分环境打包步骤(给不同的环境配置相对应的打包命令)
2019/06/04 Javascript
JS回调函数原理与用法详解【附PHP回调函数】
2019/07/20 Javascript
js实现轮播图效果 z-index实现轮播图
2020/01/17 Javascript
微信小程序全选多选效果实现代码解析
2020/01/21 Javascript
Vue的props父传子的示例代码
2020/05/20 Javascript
Vue文本模糊匹配功能如何实现
2020/07/30 Javascript
Python遍历指定文件及文件夹的方法
2015/05/09 Python
python数据类型_元组、字典常用操作方法(介绍)
2017/05/30 Python
HTML中使用python屏蔽一些基本功能的方法
2017/07/07 Python
Python中的id()函数指的什么
2017/10/17 Python
神经网络理论基础及Python实现详解
2017/12/15 Python
Python 实现字符串中指定位置插入一个字符
2018/05/02 Python
Python实现微信自动好友验证,自动回复,发送群聊链接方法
2019/02/21 Python
简单了解python 邮件模块的使用方法
2019/07/24 Python
WxPython实现无边框界面
2019/11/18 Python
关于探究python中sys.argv时遇到的问题详解
2021/02/23 Python
AmazeUI 加载进度条的实现示例
2020/08/20 HTML / CSS
英国珠宝钟表和家居礼品精品店:David Shuttle
2018/02/24 全球购物
Reformation官网:美国女装品牌
2018/09/14 全球购物
英国首屈一指的票务公司:See Tickets
2019/05/11 全球购物
以下的初始化有什么区别
2013/12/16 面试题
C#笔试题集合
2013/06/21 面试题
校本教研工作制度
2014/01/22 职场文书
大学新生军训方案
2014/05/03 职场文书
信息管理专业自荐书
2014/06/05 职场文书
体育馆的标语
2014/06/24 职场文书
离职报告格式
2014/11/04 职场文书
投诉信回复范文
2015/07/03 职场文书
六一儿童节致辞稿(3篇)
2019/07/11 职场文书