详解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 相关文章推荐
起点页面传值js,有空研究学习下
Jan 25 Javascript
从盛大通行证上摘下来的身份证验证js代码
Jan 11 Javascript
解决jquery异步按一定的时间间隔刷新问题
Dec 10 Javascript
jQuery控制TR显示隐藏的三种常用方法
Aug 21 Javascript
几种经典排序算法的JS实现方法
Mar 25 Javascript
jQuery实现的简单拖拽功能示例
Sep 13 Javascript
Angular项目从新建、打包到nginx部署全过程记录
Dec 09 Javascript
浅析Vue项目中使用keep-Alive步骤
Jul 27 Javascript
vue-cli脚手架搭建的项目去除eslint验证的方法
Sep 29 Javascript
微信小程序使用二次贝塞尔曲线画波浪
Dec 25 Javascript
利用d3.js力导布局绘制资源拓扑图实例教程
Jan 08 Javascript
微信小程序页面上下滚动效果
Nov 18 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
便携利器 — TECSUN PL-365简评
2021/03/02 无线电
PHP 5.5 创建和验证哈希最简单的方法详解
2013/11/07 PHP
php+mysql实现数据库随机重排实例
2014/10/17 PHP
php类中的各种拦截器用法分析
2014/11/03 PHP
Laravel 5框架学习之向视图传送数据(进阶篇)
2015/04/08 PHP
深入浅析Yii admin的权限控制
2016/08/31 PHP
PHP SPL 被遗落的宝石【SPL应用浅析】
2018/04/20 PHP
ThinkPHP3.1.2 使用cli命令行模式运行的方法
2020/04/14 PHP
用jscript实现新建word文档
2007/06/15 Javascript
javascript重写alert方法的实例代码
2013/03/29 Javascript
js去除空格的12种实用方法
2013/11/08 Javascript
jQuery使用attr()方法同时设置多个属性值用法实例
2015/03/26 Javascript
jQuery中toggle()函数的使用实例
2015/04/17 Javascript
JavaScript中的fontsize()方法使用详解
2015/06/08 Javascript
javascript中使用new与不使用实例化对象的区别
2015/06/22 Javascript
JavaScript 输出显示内容(document.write、alert、innerHTML、console.log)
2016/12/14 Javascript
详解用vue编写弹出框组件
2017/07/04 Javascript
jQuery Layer弹出层传值到父页面的实现代码
2017/08/17 jQuery
vue自定义指令directive的使用方法
2019/04/07 Javascript
js简单的分页器插件代码实例
2019/09/11 Javascript
jQuery实现滑动星星评分效果(每日分享)
2019/11/13 jQuery
初学Python实用技巧两则
2014/08/29 Python
详解Python import方法引入模块的实例
2017/08/02 Python
Python内置函数 next的具体使用方法
2017/11/24 Python
Python基于Logistic回归建模计算某银行在降低贷款拖欠率的数据示例
2019/01/23 Python
Pandas删除数据的几种情况(小结)
2019/06/21 Python
python实现最小二乘法线性拟合
2019/07/19 Python
利用Tensorflow构建和训练自己的CNN来做简单的验证码识别方式
2020/01/20 Python
优秀学生干部个人的自我评价
2013/10/04 职场文书
员工工作表现评语
2014/04/26 职场文书
住宅使用说明书
2014/05/09 职场文书
治安消防安全责任书
2014/07/23 职场文书
会计工作总结范文2014
2014/12/23 职场文书
质检员岗位职责
2015/02/03 职场文书
2015社区精神文明建设工作总结
2015/04/21 职场文书
2015年助理政工师工作总结
2015/05/26 职场文书