导入 * 作为“反应”的反应; 相对于导入“反应”的反应;

我注意到 React可以这样导入:

import * as React from 'react';

或者像这样:

import React from 'react';

第一个导入 react模块中的所有内容(参见: 导入整个模块的内容)

第二个只导入 default模块导出(参见: 导入默认值)


这两种方法似乎是不同的,而且根本不兼容。

为什么它们都能用?


请参考源代码和解释的机制... 我有兴趣了解这是如何工作的。


更新

这是 没有什么是进口之间的区别 * 作为反应从反应和进口反应从反应 & # 39;的复制品

这个问题的答案是一般 ES6模块信息。

我问的是使 react模块像这样工作的机制。它似乎与“ hacky”导出机制 在这里的源头有关,但目前还不清楚如何能够同时导入 完整的模块和 违约导出到 React,并且让这两种方法都可以用于翻译 JSX,等等。

47428 次浏览

You most likely have "allowSyntheticDefaultImports": true, set in your tsconfig.json, which essentially shuts the compiler up about default imports it thinks are invalid. Typescript added esModuleInterop which does essentially what babel does for module loading.

This allows you to use ES6 default imports even when the source code you're importing doesn't export anything as default

Typescript is strict (follows the rules) when it comes to this, which is why they require you to import * as React from 'react'. Or requires you to tell it to allow synthetic default imports in its base config.

More On That Here

TL;DR

Indeed ES import statements import default and import * are not the same thing, the fact that they behave the same in this case is a combination of how React authors chose to publish the library and compatibility layers in TypeScript (using esModuleInterop) or Babel and your bundler to make them "just work". It probably shouldn't work according to ES6 spec, but today we are still working in an era where JS modules are a mess, so tools like Babel, TypeScript, Webpack, etc try to normalize behavior.

More details:

React is not an ES6 library. If you look at the source code you 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 comment, even in React source code they struggle with ES6 default export compatibility.)

The module.exports = syntax is CommonJS (NodeJS). A browser would not understand this. This is why we use bundlers like Webpack, Rollup, or Parcel. They understand all kinds of module syntax and produce bundles that should work in the browser.

But even though React is not an ES library, both TypeScript and Babel let you import it as if it is (using import syntax, rather than require(), etc), but there are differences between CJS and ES that have to be resolved. One of them is the fact that export = can give you things that ES has no spec-compliant way to import, like a function or a class as the module. To work around these incompatibilities Babel has for awhile allowed you to import CJS modules as if they were exporting something by default, or import as a namespace. TypeScript for awhile didn't do this, but more recently added that as an option under esModuleInterop. So now both Babel and TypeScript can pretty consistently allow a CJS module to be imported using default or namespace ES imports.

With TypeScript it also depends on how the type-definitions for the library are actually defined. I won't get into that, but you can imagine situations where thanks to transpilers and bundlers a particular import works at runtime, but TypeScript doesn't compile without errors.

Another thing worth mentioning is that if you look at the built code for React there is a UMD module version as well as the CJS version. The UMD version includes some gnarly runtime code to try to make it work in any module environment, including the browser. It's mainly for use if you want to just include React at runtime (ie you don't use a bundler). Example.

Confusing? Yeah, I think so. :)