详解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 各浏览器的 Javascript 效率对比
Jan 23 Javascript
JavaScript的eval JSON object问题
Nov 15 Javascript
js history对象简单实现返回和前进
Oct 30 Javascript
juery框架写的弹窗效果适合新手
Nov 27 Javascript
js实现创建删除html元素小结
Sep 30 Javascript
Bootstrap每天必学之js插件
Nov 30 Javascript
jQuery Mobile和HTML5开发App推广注册页
Nov 07 Javascript
Bootstrap选项卡学习笔记分享
Feb 13 Javascript
Vue编写多地区选择组件
Aug 21 Javascript
JS匿名函数和匿名自执行函数概念与用法分析
Mar 16 Javascript
微信小程序实现倒计时调用相机自动拍照功能
Jun 10 Javascript
一文了解vue-router之hash模式和history模式
May 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往windows中添加用户
2006/12/06 PHP
asp和php下textarea提交大量数据发生丢失的解决方法
2008/01/20 PHP
使用bcompiler对PHP文件进行加密的代码
2010/08/29 PHP
php操作(删除,提取,增加)zip文件方法详解
2015/03/12 PHP
wordpress安装过程中遇到中文乱码的处理方法
2015/04/21 PHP
详解PHP对数组的定义以及数组的创建方法
2015/11/27 PHP
php实现遍历文件夹的方法汇总
2017/03/02 PHP
javascript判断ie浏览器6/7版本加载不同样式表的实现代码
2011/12/26 Javascript
深入理解javascript学习笔记(一) 编写高质量代码
2012/08/09 Javascript
探讨js字符串数组拼接的性能问题
2014/10/11 Javascript
jQuery中:lt选择器用法实例
2014/12/29 Javascript
javascript实现控制div颜色
2015/07/07 Javascript
asp.net中oracle 存储过程(图文)
2015/08/12 Javascript
深入浅析JS的数组遍历方法(推荐)
2016/06/15 Javascript
JS定时器实现数值从0到10来回变化
2016/12/09 Javascript
JS中type="button"和type="submit"的区别
2017/07/04 Javascript
vue新vue-cli3环境配置和模拟json数据的实例
2018/09/19 Javascript
详解基于Wepy开发小程序插件(推荐)
2019/08/01 Javascript
深入解析Python设计模式编程中建造者模式的使用
2016/03/02 Python
使用Python读写文本文件及编写简单的文本编辑器
2016/03/11 Python
python各种语言间时间的转化实现代码
2016/03/23 Python
Python判断一个文件夹内哪些文件是图片的实例
2018/12/07 Python
python实现代码统计器
2019/09/19 Python
python随机数分布random均匀分布实例
2019/11/27 Python
Python urlencode和unquote函数使用实例解析
2020/03/31 Python
pycharm设置默认的UTF-8编码模式的方法详解
2020/06/01 Python
波兰电子产品购物网站:Vobis
2019/05/26 全球购物
简单英文演讲稿
2014/01/01 职场文书
视光学毕业生自荐书范文
2014/02/13 职场文书
2014年家长学校工作总结
2014/11/20 职场文书
党员检讨书范文
2014/12/27 职场文书
同学会邀请函模板
2015/01/30 职场文书
导游词之无锡东林书院
2019/12/11 职场文书
golang在GRPC中设置client的超时时间
2021/04/27 Golang
Python必备技巧之字符数据操作详解
2022/03/23 Python
详解NumPy中的线性关系与数据修剪压缩
2022/05/25 Python