详解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参数列表集合
Apr 06 Javascript
JavaScript 基础篇之对象、数组使用介绍(三)
Apr 07 Javascript
js实现简单排列组合的方法
Jan 27 Javascript
js实现添加可信站点、修改activex安全设置,禁用弹出窗口阻止程序
Aug 17 Javascript
AngularJs Forms详解及简单示例
Sep 01 Javascript
VueJS全面解析
Nov 10 Javascript
AngularJS 文件上传控件 ng-file-upload详解
Jan 13 Javascript
纯js实现html转pdf的简单实例(推荐)
Feb 16 Javascript
详解如何在Angular中快速定位DOM元素
May 17 Javascript
JavaScript正则表达式的贪婪匹配和非贪婪匹配
Sep 05 Javascript
如何使用proxy实现一个简单完整的MVVM库的示例代码
Sep 17 Javascript
Javascript生成器(Generator)的介绍与使用
Jan 31 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缩略图等比例无损压缩,可填充空白区域补充色
2011/06/10 PHP
PHP中spl_autoload_register函数的用法总结
2013/11/07 PHP
PHP批量检测并去除文件BOM头代码实例
2014/05/08 PHP
PHP随手笔记整理之PHP脚本和JAVA连接mysql数据库
2015/11/25 PHP
IE 下的只读 innerHTML
2009/08/21 Javascript
js处理php输出时间戳对不上号的解决方法
2014/06/20 Javascript
node+express+jade制作简单网站指南
2014/11/26 Javascript
Jquery实现鼠标移动放大图片功能实例
2015/03/25 Javascript
Jquery $when done then的用法详解
2016/05/20 Javascript
微信小程序 框架详解及实例应用
2016/09/26 Javascript
JS实现太极旋转思路分析
2016/12/09 Javascript
浅谈js中同名函数和同名变量的执行问题
2017/02/12 Javascript
详解AngularJS脏检查机制及$timeout的妙用
2017/06/19 Javascript
基于jQuery实现手风琴菜单、层级菜单、置顶菜单、无缝滚动效果
2017/07/20 jQuery
JavaScript中构造函数与原型链之间的关系详解
2019/02/25 Javascript
基于vue+uniapp直播项目实现uni-app仿抖音/陌陌直播室功能
2019/11/12 Javascript
Python中pygal绘制雷达图代码分享
2017/12/07 Python
python实现手机通讯录搜索功能
2018/02/22 Python
python实现超市扫码仪计费
2018/05/30 Python
python爬取足球直播吧五大联赛积分榜
2018/06/13 Python
Python 常用模块 re 使用方法详解
2019/06/06 Python
python爬虫项目设置一个中断重连的程序的实现
2019/07/26 Python
Python 中的pygame安装与配置教程详解
2020/02/10 Python
Python APScheduler执行使用方法详解
2020/12/10 Python
简单掌握CSS3将文字描边及填充文字颜色的方法
2016/03/07 HTML / CSS
美国知名男士服饰品牌:Brooks Brothers(布克兄弟)
2016/08/25 全球购物
英国性能汽车零件和发动机配件在线:Maxpeedingrods
2019/11/05 全球购物
计算机应用与科学个人的自我评价
2013/11/15 职场文书
班组长安全生产职责
2013/12/16 职场文书
先进党支部事迹材料
2014/01/13 职场文书
销售人员自我评价
2014/02/01 职场文书
红旗方阵解说词
2014/02/12 职场文书
园林技术个人的自我评价
2014/02/15 职场文书
《掌声》教学反思
2014/02/23 职场文书
单位未婚证明范本
2014/11/25 职场文书
毕业班工作总结
2015/08/10 职场文书