P粉4861381962023-08-23 10:44:14
You most likely have "allowSyntheticDefaultImports": true,
set in your tsconfig.json
file, which actually makes the compiler silent on default imports it deems invalid. Typescript adds esModuleInterop
which is basically the same thing babel does in terms of module loading.
This enables you to use ES6 default imports when the imported source code does not have a default export.
Typescript is strict (follows the rules) in this regard, which is why it requires you to use import * as React from 'react'
. Or require you to tell it in the base configuration to allow synthetic default imports.
P粉0236500142023-08-23 00:04:25
Actually, the ES import statement import default
and import *
are not the same thing. They behave the same in this case because the React author chose to do it this way. Publish the library and make it "just work" using a compatibility layer in TypeScript (using esModuleInterop
) or Babel and the packaging tool. According to the ES6 spec, it probably shouldn't work properly, but today we're still in the age of JS module chaos, so tools like Babel, TypeScript, Webpack, etc. all try to standardize behavior.
React is not an ES6 library. If you look at the source code, you'll see this in 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;
(Note the comments, even in the React source code, they are working on compatibility issues with ES6 default exports.)
module.exports =
The syntax is that of CommonJS (NodeJS). The browser cannot understand this syntax. That's why we use packaging tools like Webpack, Rollup or Parcel. They understand various module syntaxes and generate bundled files that should work in the browser.
However, even though React is not an ES library, both TypeScript and Babel allow you to import it like an ES library (using the import
syntax, not require()
, etc.) , but there are some differences between CJS and ES that need to be addressed. One of them is that export =
can provide you with import methods that are not compliant with the ES specification, such as importing functions or classes as modules. To resolve these incompatibilities, Babel allows you to import CJS modules by default, or by namespace. TypeScript did not previously support this, but this option was recently added under esModuleInterop
. So now both Babel and TypeScript fairly consistently allow importing CJS modules using default or namespace ES imports.
For TypeScript, it also depends on how the library's type definition is defined. I won't go into details, but you can imagine that there are cases where a specific import will work fine at runtime due to the transpiler and packaging tools, but TypeScript will throw errors at compile time.
Another thing worth mentioning is that if you look at React's build code, there is also a UMD module version as well as a CJS version. The UMD version contains some complex runtime code to make it work properly in any module environment, including browsers. It is mainly intended for use when only React is included in the runtime (i.e. no packaging tools are used). Example.
Confusing? Yes, I think so too. :)