详解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 相关文章推荐
Extjs Ajax 乱码问题解决方案
Apr 15 Javascript
javascript 面向对象编程  function是方法(函数)
Sep 17 Javascript
Javascript 面向对象(三)接口代码
May 23 Javascript
onbeforeunload与onunload事件异同点总结
Jun 24 Javascript
分享9点个人认为比较重要的javascript 编程技巧
Apr 27 Javascript
JavaScript中继承用法实例分析
May 16 Javascript
AngularJS页面访问时出现页面闪烁问题的解决
Mar 06 Javascript
深入解析jQuery中Deferred的deferred.promise()方法
May 03 Javascript
jQuery中页面返回顶部的方法总结
Dec 30 Javascript
详解Vue快速零配置的打包工具——parcel
Jan 16 Javascript
vue-simple-uploader上传成功之后的response获取代码
Sep 07 Javascript
vue @ ~ 相对路径 路径别名设置方式
Jun 05 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
新52大事件
2020/03/03 欧美动漫
php 分页函数multi() discuz
2009/06/21 PHP
PHP开发环境配置(MySQL数据库安装图文教程)
2010/04/28 PHP
PHP Ajax JavaScript Json获取天气信息实现代码
2016/08/17 PHP
JavaScript For Beginners(转载)
2007/01/05 Javascript
jQuery表单验证插件formValidator(改进版)
2012/02/03 Javascript
JS实现金额转换(将输入的阿拉伯数字)转换成中文的实现代码
2013/09/30 Javascript
js复制网页内容并兼容各主流浏览器的代码
2013/12/17 Javascript
jquery实现TAB选项卡鼠标经过带延迟效果的方法
2015/07/27 Javascript
Jquery删除css属性的简单方法
2016/12/04 Javascript
js正则表达式验证密码强度【推荐】
2017/03/03 Javascript
jQuery实现获取table中鼠标click点击位置行号与列号的方法
2017/10/09 jQuery
解决Jquery下拉框数据动态获取的问题
2018/01/25 jQuery
jQuery niceScroll滚动条错位问题的解决方法
2018/02/03 jQuery
Vue项目报错:Uncaught SyntaxError: Unexpected token
2018/11/10 Javascript
使用layui的layer组件做弹出层的例子
2019/09/27 Javascript
[01:19:34]2014 DOTA2国际邀请赛中国区预选赛 New Element VS Dream time
2014/05/22 DOTA
[04:03][TI9趣味短片] 小鸽子茶话会
2019/08/20 DOTA
[01:28:44]DOTA2-DPC中国联赛定级赛 RNG vs iG BO3第一场 1月10日
2021/03/11 DOTA
Python GAE、Django导出Excel的方法
2008/11/24 Python
python删除文件示例分享
2014/01/28 Python
python实现的文件夹清理程序分享
2014/11/22 Python
python3音乐播放器简单实现代码
2020/04/20 Python
pandas按若干个列的组合条件筛选数据的方法
2018/04/11 Python
Django错误:TypeError at / 'bool' object is not callable解决
2019/08/16 Python
python多进程间通信代码实例
2019/09/30 Python
python实现拉普拉斯特征图降维示例
2019/11/25 Python
pyqt5中动画的使用详解
2020/04/01 Python
Python json解析库jsonpath原理及使用示例
2020/11/25 Python
营销与策划个人求职信
2013/09/22 职场文书
开办饭店创业计划书
2013/12/28 职场文书
元宵节晚会主持人串词
2014/03/25 职场文书
勾股定理课后反思
2014/04/26 职场文书
2015年全国保险公众宣传日活动方案
2015/05/06 职场文书
LayUI+Shiro实现动态菜单并记住菜单收展的示例
2021/05/06 Javascript
Spring Boot 整合 Apache Dubbo的示例代码
2021/07/04 Java/Android