- 原文地址:TypeScript With Babel: A Beautiful Marriage
- 原文作者:Matt Turnbull
- 譯文出自:掘金翻譯計劃
- 本文永久連結:github.com/xitu/gold-m…
- 譯者:zsky
- 校對者:xionglong58, brilliantGuo
由於 TypeScript 和 Babel 團隊官方合作了一年的專案:TypeScript plugin for Babel(@babel/preset-typescript
),TypeScript 的使用變得比以往任何時候都容易。這篇文章會告訴你為何 TypeScript 和 Babel 是完美配對的 4 點原因,並會教你在 10 分鐘內一步步地升級到 TypeScript。
哈?什麼?為什麼?
我一開始並不理解這個 preset 的必要性。
Babel 和 TypeScript 不是兩個完全不一樣的東西麼?Babel 能怎麼處理 TypeScript 的型別檢查?TypeScript 早已能像 Babel 一樣輸出 ES5 程式碼,這有什麼意義呢?把 Babel 和 TypeScript 合併起來不是會把事情複雜化麼?
在幾個小時的調研後,我的結論是:
TypeScript 和 Babel 是美麗的結合。
讓我來告訴你原因。
1)你早已使用 Babel(或者應該如此)
你屬於這三個類別之一:
- 你早已使用 Babel。如果不是直接使用,你的 Webpack 配置會把
*.js
檔案提供給 Babel(大多數腳手架都是這種情況,包括 create-react-app) - 使用了 TypeScript,卻沒有用 Babel。針對這種情況,你可以考慮把 Babel 加入你的武器庫中,因為它提供了許多獨特的功能。繼續閱讀,你會了解更多!
- 你不使用 Babel?是時候開始用了。
編寫現代 JavaScript 而不破壞任何東西
你的 JavaScript 程式碼需要在舊瀏覽器中執行?沒問題,Babel 會轉換程式碼,而且不會出現任何問題。使用最新和最好的功能,無需擔心。
TypeScript 編譯器具有類似的功能,可通過將 target
設定為 ES5
或 ES6
來實現。但 Babel 配置通過 babel-preset-env 改進了這方面功能。你可以列出需要支援的環境,而不是鎖定一組特定的 JavaScript 功能(ES5,ES6 等):
"targets": {
"browsers": ["last 2 versions", "safari >= 7"],
"node": "6.10"
}
複製程式碼
Babel 使用 compat-table 來檢查要轉換的 JavaScript 功能以及針對這些特定目標環境做 polyfill。
花點時間欣賞那個將這個專案命名為 ‘compat-table’ 的天才。
create-react-app 使用了一種有趣的技術:在開發期間以最新的瀏覽器進行編譯(為了速度),並在生產中以更大範圍的瀏覽器進行編譯(為了相容性)。漂亮。
Babel 是超級可配置的
想要 JSX? Flow?TypeScript?只需安裝一個外掛,Babel 就可以處理它。有大量的 官方外掛,主要涵蓋即將推出的 JavaScript 語法。 還有很多第三方外掛:improve lodash imports,enhance console.log,或 strip console.log。在 awesome-babel 列表中找到更多資訊。
不過要小心。如果外掛顯著改變了語法,那麼 TypeScript 可能無法解析它。例如,備受期待的 optional chaining proposal 提議有一個 Babel 外掛:
@babel/plugin-proposal-optional-chaining
但不幸的是,TypeScript 無法理解這種更新的語法。
不要緊張,有另一種選擇...
Babel 巨集
你知道 Kent C Dodds 嗎?他創造了一個改變遊戲規則的 Babel 外掛:babel-plugin-macros。
你可以將巨集安裝為依賴項並將其匯入程式碼中,而不是將外掛新增到 Babel 配置檔案中。當 Babel 正在編譯時,巨集會啟動,並根據需要修改程式碼。
來看一個例子。 它使用 idx.macro 來解決痛點,直到 optional chaining proposal 提議通過:
import idx from 'idx.macro';
const friends = idx(
props,
_ => _.user.friends[0].friends
);
複製程式碼
編譯為:
const friends =
props.user == null ? props.user :
props.user.friends == null ? props.user.friends :
props.user.friends[0] == null ? props.user.friends[0] :
props.user.friends[0].friends
複製程式碼
巨集是相當新的,但很快就越來越受歡迎。特別是整合在 create-react-app v2.0 後。 CSS in JS 被覆蓋:styled-jsx、styled-components 和 emotion。Webpack 外掛在被移植中:raw-loader、url-loader 和 filesize-loader。還有更多列在 awesome-babel-macros。
這是最好的部分:與 Babel 外掛不同,所有 Babel 巨集都與 TypeScript 相容。它們還可以幫助減少執行時依賴,避免一些客戶端計算,並在構建時提前捕獲錯誤。 檢視 此帖子 瞭解更多詳情。
更好的 console.log:scope.macro
2)管理一個編譯器更容易
TypeScript 需要它自己的編譯器 — 它提供了驚人的型別檢查超能力。
令人沮喪的日子(在 Babel 7 之前)
將兩個獨立的編譯器(TypeScript 和 Babel)連結在一起並非易事。編譯流程變為:TS > TS Compiler > JS > Babel > JS (again)
。
Webpack 經常用於解決這個問題。調整 Webpack 配置以將 *.ts
提供給 TypeScript,然後將結果提供給 Babel。但是你使用哪種 TypeScript loader?兩個流行的選擇是 ts-loader 和 awesome-typescript-loader。awesome-typescript-loader 的 README.md
提到它對一些工作負載來說可能更慢,並建議使用 ts-loader 加上 HappyPack 或 thread-loader。ts-loader 的 README.md
推薦結合 fork-ts-checker-webpack-plugin,HappyPack,thread-loader,和(或)cache-loader。
啊。不。這是大多數人不堪重負的地方,並把 TypeScript 放在“太難”的籃子裡。我不怪他們。
陽光燦爛的日子(有了 Babel 7)
擁有一個 JavaScript 編譯器不是很好嗎?無論你的程式碼是否具有 ES2015、JSX、TypeScript 或瘋狂的自定義功能 - 編譯器都知道該怎麼做。
我只是描述了 Babel。厚臉皮了。
通過允許 Babel 充當單個編譯器,不需要使用一些複雜的 Webpack 魔術來管理,配置或合併兩個編譯器。
它還簡化了整個 JavaScript 生態系統。他們只需要支援 Babel,而不是支援不同編譯器的語法檢查、測試執行器、構建系統和腳手架。然後,配置 Babel 以滿足你的特定需求。告別 ts-node、ts-jest、ts-karma 和 create-react-app-typescript 等,並使用 Babel 支援代替。對 Babel 的支援無處不在,請檢視 Babel 設定 頁面:
3)編譯速度更快
警告!有一個震驚的訊息,你可能想坐下來好好聽下。
Babel 如何處理 TypeScript 程式碼?它刪除它。
是的,它刪除了所有 TypeScript,將其轉換為“常規的” JavaScript,並繼續以它自己的方式愉快處理。
這聽起來很荒謬,但這種方法有兩個很大的優勢。
第一個優勢:️⚡️閃電般快速⚡️。
大多數 Typescript 開發人員在開發/監視模式下經歷過編譯時間長的問題。你正在編寫程式碼,儲存一個檔案,然後...它來了...再然後...最後,你看到了你的變更。哎呀,錯了一個字,修復,儲存,然後...啊。它只是慢得令人煩惱並打消你的勢頭。
很難去指責 TypeScript 編譯器,它在做很多工作。它在掃描那些包括 node_modules
在內的型別定義檔案(*.d.ts
),並確保你的程式碼正確使用。這就是為什麼許多人將 Typescript 型別檢查分到一個單獨的程式。然而,Babel + TypeScript 組合仍然提供更快的編譯,這要歸功於 Babel 的高階快取和單檔案發射架構。
因此,如果 Babel 剝離掉 TypeScript 程式碼,那麼編寫 TypeScript 有什麼意義呢?這帶來了第二個優勢...
4)只有在準備好後才檢查型別錯誤
你為了快速做出一個解決方案來看看你的想法是否有根據,會把一些程式碼改到一起。當你按下儲存按鈕的時候,TypeScript 向你尖叫:
“不!我不會編譯這個!你的程式碼在 42 個不同的檔案中有問題!”
是的,你知道它已經不能執行了。你可能也破壞了一些單元測試。但是你只是在這一點上進行實驗。要在所有時間持續確保所有程式碼是型別安全的,這一點讓人火大。
這是 Babel 在編譯期間剝離 TypeScript 程式碼的第二個優點。你編寫程式碼,儲存,並且編譯(非常快)而不檢查型別安全性。繼續嘗試解決方案,直到你準備好檢查程式碼是否有錯誤。這種工作流程可讓你在編碼時保持專注。
那麼如何檢查型別錯誤?新增一個呼叫 TypeScript 編譯器的 npm run check-types
指令碼。我將我的 npm test
命令調整為首先檢查型別,然後繼續執行單元測試。
這不是完美的結合
根據 公告文章,有四種 TypeScript 功能由於其單檔案發射架構而無法在 Babel 中編譯。
別擔心,它沒有那麼糟糕。當啟用 isolatedModules
標誌時,TypeScript 將對這些問題發出警告。
1)名稱空間。
解決方案:不要使用它們!他們已經過時了。請改用行業標準 ES6 模組(import
/ export
)。推薦 tslint 規則 確保名稱空間不被使用。
2)使用<newtype>x
語法轉換型別。
解決方案:使用 x as newtype
。
3)Const 列舉。
這很羞愧。現在需要使用常規列舉。
4)傳統風格的 import / export 語法。
示例:import foo = require(...)
和 export = foo
。
在我多年 TypeScript 的使用中,我從未遇到過這種情況。誰這樣編碼?停下來!
好的,我準備嘗試使用 Babel 和 TypeScript!
由 rawpixel.com 拍攝
我們開工吧!它應該只需要大約 10 分鐘。
我假設你設定了 Babel 7。如果沒有,請參閱 Babel 遷移指南。
1)將 .js 檔案重新命名為 .ts
假設你的檔案位於 /src
中:
find src -name "*.js" -exec sh -c 'mv "$0" "${0%.js}.ts"' {} ;
複製程式碼
2)將 TypeScript 新增到 Babel。
安裝一些依賴:
npm install --save-dev @babel/preset-typescript @babel/plugin-proposal-class-properties @babel/plugin-proposal-object-rest-spread
複製程式碼
在你的 Babel 配置檔案裡(.babelrc
或 babel.config.js
)新增:
{
"presets": [
"@babel/typescript"
],
"plugins": [
"@babel/proposal-class-properties",
"@babel/proposal-object-rest-spread"
]
}
複製程式碼
TypeScript 有一些 Babel 需要了解的額外功能(通過上面列出的兩個外掛)。
Babel 預設查詢 .js 檔案,遺憾的是,這在 Babel 配置檔案中是不可配置的。
如果你使用 Babel CLI,新增 --extensions '.ts'
如果你使用 Webpack,新增 'ts'
到 resolve.extensions
陣列。
3)新增 “check-types” 命令。
在 package.json
裡新增:
"scripts": {
"check-types": "tsc"
}
複製程式碼
這個命令只是簡單地呼叫 TypeScript 編譯器(tsc
)。
tsc
來自哪裡?我們需要安裝 TypeScript:
npm install --save-dev typescript
複製程式碼
為了配置 TypeScript(和 tsc
),我們需要在根目錄下有 tsconfig.json
檔案:
{
"compilerOptions": {
// Target latest version of ECMAScript.
"target": "esnext",
// Search under node_modules for non-relative imports.
"moduleResolution": "node",
// Process & infer types from .js files.
"allowJs": true,
// Don't emit; allow Babel to transform files.
"noEmit": true,
// Enable strictest settings like strictNullChecks & noImplicitAny.
"strict": true,
// Disallow features that require cross-file information for emit.
"isolatedModules": true,
// Import non-ES modules as default imports.
"esModuleInterop": true
},
"include": [
"src"
]
}
複製程式碼
完成。
好了,設定完成了。現在執行 npm run check-types
(監聽模式:npm run check-types -- --watch
)並確保 TypeScript 對你的程式碼滿意。你可能會發現一些你不知道但卻存在的錯誤。這是件好事!這份 從 Javascript 遷移 指南也會給你一些幫助。
Microsoft 的 TypeScript-Babel-Starter 指南包含其他設定說明,包括從頭開始安裝 Babel,生成型別定義(d.ts)檔案,以及將其與 React 一起使用。
關於語法檢查呢?
使用 tslint。
更新(2019 年 2 月):使用 ESlint!自1月份以來,TypeScript 團隊一直 專注於 ESLint 整合。由於 @typesript-eslint 專案,很容易配置 ESLint。如需參考,請檢視我的 超級 ESLint 配置,其中包括 TypeScript、Airbnb、Prettier 和 React。
Babel + TypeScript = 美麗的結合
由 Akshar Dave 拍攝
Babel 是你需要的唯一一個 JavaScript 編譯器。它可以被配置去處理任何事情。
沒有必要與兩個相互競爭的 JavaScript 編譯器鬥爭。簡化你的專案配置,並充分利用 Babel 與語法檢查、測試執行器、構建系統和腳手架的驚人整合。
Babel 和 TypeScript 組合可以快速編譯,並允許你專注地編碼,只有在你準備好時才檢查型別。
預測:TypeScript 使用將會上升
根據最新的 Stack Overflow 開發者調查,JavaScript 是最流行的語言,TypeScript 排在第 12 位。 對於TypeScript 來說,這仍然是一項偉大的成就,擊敗了 Ruby、Swift 和 Go。
我預測 TypeScript 將在明年進入前 10 名。
TypeScript 團隊正在努力推廣。這個 Babel preset 是為期一年的合作,他們的新焦點是在 改進 ESLint 整合。這是一個聰明的舉措 — 利用現有工具的功能、社群和外掛。開發有競爭力的編譯器和語法檢查是浪費精力。
通往 TypeScript 的路徑已經被鋪平了,我們只需調整我們喜愛的工具配置即可。進入的障礙已被打破。
隨著 VS Code 的普及,開發人員已經設定了一個很棒的 TypeScript 環境。寫程式碼時的自動補全將帶來歡樂的淚水。
它現在也整合到 create-react-app v2.0 中,將 TypeScript 展現給每月有 20 萬次下載的使用者。
如果你因為設定太難而推遲使用 TypeScript,這不再是一個藉口。是時候試一試了。
如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。
掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 Android、iOS、前端、後端、區塊鏈、產品、設計、人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃、官方微博、知乎專欄。