详解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 按回车键相应按钮提交事件
Nov 02 Javascript
onkeypress字符按键兼容所有浏览器使用介绍
Apr 24 Javascript
禁止空格提交表单的js代码
Nov 17 Javascript
jQuery控制TR显示隐藏的几种方法
Jun 18 Javascript
Javascript无参数和有参数类继承问题解决方法
Mar 02 Javascript
js实现图片放大和拖拽特效代码分享
Sep 05 Javascript
JavaScript编程学习技巧汇总
Feb 21 Javascript
分享一个精简的vue.js 图片lazyload插件实例
Mar 13 Javascript
Angular模版驱动表单的使用总结
May 05 Javascript
vue中引入第三方字体文件的方法示例
Dec 17 Javascript
JS数组方法join()用法实例分析
Jan 18 Javascript
WEB前端性能优化的7大手段详解
Feb 04 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
全国FM电台频率大全 - 26 西藏自治区
2020/03/11 无线电
PHP utf-8编码问题,utf8编码,数据库乱码,页面显示输出乱码
2013/04/08 PHP
php解析html类库simple_html_dom(详细介绍)
2013/07/05 PHP
PHP小技巧之函数重载
2014/06/02 PHP
php中操作memcached缓存进行增删改查数据的实现代码
2014/08/15 PHP
php筛选不存在的图片资源
2015/04/28 PHP
PHP判断字符串长度的两种方法很实用
2015/09/22 PHP
php实现可运算的验证码
2015/11/10 PHP
工作中常用到的JS表单验证代码(包括例子)
2010/11/11 Javascript
jquery和javascript中如何将一元素的内容赋给另一元素
2014/01/09 Javascript
jquery移除、绑定、触发元素事件使用示例详解
2014/04/10 Javascript
使用mouse事件实现简单的鼠标经过特效
2015/01/30 Javascript
js实现图片从左往右渐变切换效果的方法
2015/02/06 Javascript
基于JS实现导航条flash导航条
2016/06/17 Javascript
jQuery增加、删除及修改select option的方法
2016/08/19 Javascript
浅谈Vue父子组件和非父子组件传值问题
2017/08/22 Javascript
JavaScript实现鼠标滚轮控制页面图片切换功能示例
2017/10/14 Javascript
小程序自定义导航栏兼容适配所有机型(附完整案例)
2020/04/26 Javascript
详解如何在Javascript中使用Object.freeze()
2020/10/18 Javascript
vue常用高阶函数及综合实例
2021/02/25 Vue.js
python中的五种异常处理机制介绍
2014/09/02 Python
Python使用urllib模块的urlopen超时问题解决方法
2014/11/08 Python
深入讲解Python函数中参数的使用及默认参数的陷阱
2016/03/13 Python
Python对象属性自动更新操作示例
2018/06/15 Python
BP神经网络原理及Python实现代码
2018/12/18 Python
Django 查询数据库并返回页面的例子
2019/08/12 Python
python进程间通信Queue工作过程详解
2019/11/01 Python
手把手教你配置JupyterLab 环境的实现
2021/02/02 Python
html5 localStorage本地存储_动力节点Java学院整理
2017/07/06 HTML / CSS
一份全面的PHP面试问题考卷
2012/07/15 面试题
个人租房协议书
2014/11/28 职场文书
2014年高中教师工作总结
2014/12/19 职场文书
公司借款担保书
2015/09/22 职场文书
2019年世界儿童日宣传标语
2019/11/22 职场文书
如何在CocosCreator里画个炫酷的雷达图
2021/04/16 Javascript
Elasticsearch 数据类型及管理
2022/04/19 Python