详解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 相关文章推荐
12个非常有创意的JavaScript小游戏
Mar 18 Javascript
使用jQuery validate 验证注册表单实例演示
Mar 25 Javascript
基于pthread_create,readlink,getpid等函数的学习与总结
Jul 17 Javascript
js实现可拖动DIV的方法
Dec 17 Javascript
Extjs 4.x 得到form CheckBox 复选框的值
May 04 Javascript
js类定义函数时用prototype与不用的区别示例介绍
Jun 10 Javascript
jQuery通过点击行来删除HTML表格行的实现示例
Sep 10 Javascript
jQuery的animate函数实现图文切换动画效果
May 03 Javascript
JS继承之借用构造函数继承和组合继承
Sep 07 Javascript
JavaScript制作弹出层效果
Dec 02 Javascript
JS数组进阶示例【数组的几种函数用法】
Jan 16 Javascript
详解node和ES6的模块导出与导入
Feb 19 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 similar_text 字符串的相似性比较函数
2010/05/26 PHP
Discuz Uchome ajaxpost小技巧
2011/01/04 PHP
PHP根据传入参数合并多个JS和CSS文件的简单实现
2014/06/13 PHP
PHP ignore_user_abort函数详细介绍和使用实例
2014/07/15 PHP
php使用ffmpeg向视频中添加文字字幕的实现方法
2016/05/23 PHP
PHP之将POST数据转化为字符串的实现代码
2016/11/03 PHP
PHP页面静态化――纯静态与伪静态用法详解
2020/06/05 PHP
游戏人文件夹程序 ver 4.03
2006/07/14 Javascript
一个简单的JavaScript数据缓存系统实现代码
2010/10/24 Javascript
使用jquery实现select添加实现后台权限添加的效果
2011/05/28 Javascript
js图片实时加载提供网页打开速度
2014/09/11 Javascript
jQuery找出网页上最高元素的方法
2015/03/20 Javascript
JSON对象 详解及实例代码
2016/10/18 Javascript
Bootstrap select多选下拉框实现代码
2016/12/23 Javascript
js生成随机数方法和实例
2017/01/17 Javascript
Angular 2父子组件数据传递之@ViewChild获取子组件详解
2017/07/04 Javascript
详解EasyUi控件中的Datagrid
2017/08/23 Javascript
vue中的$emit 与$on父子组件与兄弟组件的之间通信方式
2018/05/13 Javascript
微信小程序常用简易小函数总结
2019/02/01 Javascript
了解Javascript中函数作为对象的魅力
2019/06/19 Javascript
JavaScript实现单图片上传并预览功能
2019/09/30 Javascript
微信小程序整个页面的自动适应布局的实现
2020/07/12 Javascript
浅谈vue项目利用Hbuilder打包成APP流程,以及遇到的坑
2020/09/12 Javascript
用python写asp详细讲解
2013/12/16 Python
windows系统中python使用rar命令压缩多个文件夹示例
2014/05/06 Python
numpy数组拼接简单示例
2017/12/15 Python
基于Python开发chrome插件的方法分析
2018/07/07 Python
pycharm新建Vue项目的方法步骤(图文)
2020/03/04 Python
python主要用于哪些方向
2020/07/05 Python
土木工程毕业生推荐信
2013/10/28 职场文书
《特殊的葬礼》教学反思
2014/04/27 职场文书
领导班子三严三实对照检查材料
2014/09/25 职场文书
社区法制宣传日活动总结
2015/05/05 职场文书
体育委员竞选稿
2015/11/21 职场文书
python使用tkinter实现透明窗体上绘制随机出现的小球(实例代码)
2021/05/17 Python
Win11查看设备管理器
2022/04/19 数码科技