I noticed that React
can be imported like this:
import * as React from 'react';
...or import like this:
import React from 'react';
The first method imports all the contents of the react
module (see: Importing the contents of the entire module)
The second method only imports the default
module export (see: Importing the default export)
The two approaches appear to be different and fundamentally incompatible.
Why do they all work?
Please refer to the source code and explain the mechanism... I'm interested in understanding how this works.
Update
This is not a duplicate question, it is different from "the difference between import * as react from 'react' vs import react from 'react'"
That question is answered with general ES6 module information.
I'm asking about the mechanism that enables the react
module to work this way. It seems to have something to do with a "hacky" export mechanism in the source code, but it's not clear how it makes both ways of importing the entire module and just importing the default exports to React
work with transpiled JSX etc.
You most likely have
"allowSyntheticDefaultImports": true,
set in yourtsconfig.json
file, which actually makes the compiler silent on default imports it deems invalid. Typescript addsesModuleInterop
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.More related information
TL;DR
Actually, the ES import statement
import default
andimport *
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 (usingesModuleInterop
) 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.more details:
React is not an ES6 library. If you look at thesource code, you'll see this in
index.js
:(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, notrequire()
, etc.) , but there are some differences between CJS and ES that need to be addressed. One of them is thatexport =
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 underesModuleInterop
. 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 aUMD moduleversion 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. :)