为什么要使用 import * as React from 'react' ?

764 阅读2分钟
import * as React from 'react'
import React from 'react'

这两个 import 语句理应有不同的含义,分别为:

  • 引入 react所有导出模块并定义别名为 React
  • 引入 react 导出的默认模块并定义别名为 React

但在实际运用中,似乎两条语句总是可以达成相同的结果。可是为什么第一种写法可以实现第二种写法的功能呢?

React 的模块管理方式

首先我们要知道,react 为了代码可以运行在不同的平台上,会将 ES6 代码使用 Babel 转译为 commonjs 的模块标准,也就是说实际上它的导出方式是:

// react.js
function Components(){

}

function Fragment(){
    
}

module.exports = {
	Components,
	Fragment,
	...
}
// 注意,react没有提供默认导出 module.exports.default = x

现在我们用 import React from 'react' 引入这个文件:

// main.js
import React from 'react'

console.log(React);

当时浏览器还只能运行支持 commonjs 的ES5,所以还要通过 Babel 进行转译:

// lib/main.js
"use strict";

var _react = _interopRequireDefault(require("./react"));
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
console.log(_react["default"]);

运行这个转译后的文件,可以得到打印结果:

{ Components: [Function: Components], Fragment: [Function: Fragment] }

现在把时间拨近,es-module 成为了浏览器原生支持的模块系统,import 语句不再需要编译也可以被浏览器所解析,此时我们在一个 typescript 项目中再次写下:

// main2.ts

import React from './react'

console.log(React);

我们期望它能正确运行,但错误却发生了:

模块“"/src/react"”没有默认导出。

编译器希望 /src/react 提供一个 module.exports.default 作为默认导出。但是显然 react 并没有提供这个默认模块。于是我们被迫要写上:

// main2.ts

import * as React from './react'

console.log(React);

即引入 react所有导出模块并定义别名为 React 。 这样才能正确导入 react 包。

新的疑问

但如果你在项目中使用 import React from 'react' 。你会发现它可以正确运行。我刚才说的报错是胡说八道? 当然不是。 这是因为 typescript 为了处理这种 commonjs 和 es-module 的兼容性问题而提供了一些配置上的解决方案:

/* tsconfig.json */
{
  "compilerOptions": {
	"allowJs": true, 
	// "allowSyntheticDefaultImports" : true , 
	"esModuleInterop" : true, 
  }
}
  • allowJs 允许 ts 项目中引入 js 文件
  • allowSyntheticDefaultImports : 当一个模块没有默认导出时,允许 import x from y
  • esModuleInterop : 编译时添加额外的 js 代码以缓解对导入CommonJS模块的支持,启动它时会默认将 allowSyntheticDefaultImports 设置为 true.

关于这些配置更加详细的信息可以参考:typescipt文档

总结

  • 使用 import * as React from 'react' 是为了兼容 react 在分发包时使用的 commonjs 标准的模块导出语句
  • typescript 提供了一些配置属性,在将 typesciprt 代码编译为 javascript 代码时处理了 commonjs 与 es-module 的兼容性问题。