P粉4861381962023-08-23 10:44:14
你的 tsconfig.json
文件中很可能设置了 "allowSyntheticDefaultImports": true,
,这实际上让编译器对它认为无效的默认导入保持静默。Typescript 添加了 esModuleInterop
,它基本上与 babel 在模块加载方面做的事情相同。
这使你能够在导入的源代码没有默认导出时使用 ES6 默认导入。
Typescript 在这方面是严格的(遵循规则),这就是为什么它要求你使用 import * as React from 'react'
。或者要求你在基本配置中告诉它允许合成默认导入。
P粉0236500142023-08-23 00:04:25
实际上,ES的import语句import default
和import *
并不是同一回事,它们在这种情况下表现相同是因为React作者选择以这种方式发布库并在TypeScript(使用esModuleInterop
)或Babel以及打包工具中使用兼容层使其“正常工作”。根据ES6规范,它可能不应该正常工作,但是今天我们仍然处于JS模块混乱的时代,因此像Babel、TypeScript、Webpack等工具都试图规范行为。
React不是一个ES6库。如果你查看源代码,你会在index.js
中看到这个:
const React = require('./src/React'); // TODO: decide on the top-level export form. // This is hacky but makes it work with both Rollup and Jest. module.exports = React.default || React;
(注意注释,即使在React源代码中,他们也在努力解决ES6默认导出的兼容性问题。)
module.exports =
语法是CommonJS(NodeJS)的语法。浏览器无法理解这个语法。这就是为什么我们使用像Webpack、Rollup或Parcel这样的打包工具。它们理解各种模块语法,并生成应该在浏览器中工作的打包文件。
但是,尽管React不是一个ES库,但是TypeScript和Babel都允许你像导入ES库一样导入它(使用import
语法,而不是require()
等),但是CJS和ES之间存在一些需要解决的差异。其中之一是export =
可以为你提供ES没有规范兼容的导入方式,比如将函数或类作为模块导入。为了解决这些不兼容性问题,Babel允许你以默认方式导入CJS模块,或者以命名空间方式导入。TypeScript以前不支持这样做,但是最近在esModuleInterop
下添加了这个选项。因此,现在Babel和TypeScript都可以相当一致地允许使用默认或命名空间ES导入来导入CJS模块。
对于TypeScript来说,还取决于库的类型定义是如何定义的。我不会详细介绍,但你可以想象在某些情况下,由于转译器和打包工具的原因,特定的导入在运行时可以正常工作,但TypeScript在编译时会出现错误。
另一个值得一提的事情是,如果你查看React的构建代码,还有一个UMD模块版本以及CJS版本。UMD版本包含一些复杂的运行时代码,以使其在任何模块环境中(包括浏览器)正常工作。它主要用于在运行时仅包含React(即不使用打包工具)的情况下使用。示例。
令人困惑吗?是的,我也这么认为。:)