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(即不使用打包工具)的情況下使用。 範例。
令人困惑嗎?是的,我也這麼認為。 :)