详解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 相关文章推荐
JQuery 网站换肤功能实现代码
Nov 02 Javascript
在javascript将NodeList作为Array数组处理的方法
Jul 09 Javascript
浅析js中取绝对值的2种方法
Jul 09 Javascript
网站基于flash实现的Banner图切换效果代码
Oct 14 Javascript
常用的Javascript数据验证插件
Aug 04 Javascript
一道关于JavaScript变量作用域的面试题
Mar 08 Javascript
详解Node.Js如何处理post数据
Sep 19 Javascript
微信小程序 检查接口状态实例详解
Jun 23 Javascript
vue项目搭建以及全家桶的使用详细教程(小结)
Dec 19 Javascript
vue配置font-awesome5的方法步骤
Jan 27 Javascript
koa-passport实现本地验证的方法示例
Feb 20 Javascript
vue实现放大镜效果
Sep 17 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
《忧国的莫里亚蒂》先导宣传图与STAFF公开
2020/03/04 日漫
Php注入点构造代码
2008/06/14 PHP
PHP 的异常处理、错误的抛出及回调函数等面向对象的错误处理方法
2012/12/07 PHP
解析mysql 表中的碎片产生原因以及清理
2013/06/22 PHP
微信公众平台开发之配置与请求
2015/08/26 PHP
PHP中str_split()函数的用法讲解
2019/04/11 PHP
php过滤htmlspecialchars() 函数实现把预定义的字符转换为 HTML 实体用法分析
2019/06/25 PHP
phpQuery采集网页实现代码实例
2020/04/02 PHP
eval的两组性能测试数据
2012/08/17 Javascript
jquery等宽输出文字插件使用介绍
2013/09/18 Javascript
原生js操作checkbox用document.getElementById实现
2013/10/12 Javascript
使用jQuery实现的掷色子游戏动画效果
2014/03/14 Javascript
使用js实现的简单拖拽效果
2015/03/18 Javascript
深入理解逻辑表达式的用法 与或非的用法
2016/06/06 Javascript
js css3实现图片拖拽效果
2017/03/04 Javascript
js实现3D图片展示效果
2017/03/09 Javascript
js遍历获取表格内数据的方法(必看)
2017/04/06 Javascript
vue 请求后台数据的实例代码
2017/06/22 Javascript
微信小程序checkbox组件使用详解
2018/01/31 Javascript
layui点击按钮添加可编辑的一行方法
2018/08/15 Javascript
vue-cli3 项目优化之通过 node 自动生成组件模板 generate View、Component
2019/04/30 Javascript
微信小程序自定义组件实现环形进度条
2020/11/17 Javascript
Django 导出 Excel 代码的实例详解
2017/08/11 Python
基于Python的ModbusTCP客户端实现详解
2019/07/13 Python
解决pytorch GPU 计算过程中出现内存耗尽的问题
2019/08/19 Python
用Python实现校园通知更新提醒功能
2019/11/23 Python
玛蒂尔达简服装:Matilda Jane Clothing
2019/02/13 全球购物
美国摩托车头盔、零件、齿轮及配件商店:Cycle Gear
2019/06/12 全球购物
大学生怎样进行自我评价
2013/12/07 职场文书
《苏珊的帽子》教学反思
2014/04/07 职场文书
健康家庭事迹材料
2014/05/02 职场文书
地球物理学专业推荐信
2014/09/08 职场文书
物流仓管员岗位职责
2015/04/01 职场文书
Python3 类型标注支持操作
2021/06/02 Python
解决Mysql多行子查询的使用及空值问题
2022/01/22 MySQL
基于Android10渲染Surface的创建过程
2022/08/14 Java/Android