Flow與Typescript:哪個更適合你的項目?
隨著 JavaScript 項目變得越來越復雜,開發者開發了新的工具和語言來提高代碼質量和工作流程。
除了單元測試,TypeScript 和 Flow 等靜態類型檢查器正在成為專業開發團隊的標準。無論項目大小,使代碼更易于理解并在開發階段捕獲錯誤的好處已被證明是非常有用的。
在沒有使用類型檢查工具的情況下處理大型 JavaScript 代碼庫會讓你感到頭痛,特別是那些在運行時才會發現的錯誤會產生很多,但是當你采用了類型檢查,或者使用了TypeScript之后,你會發現這些類型的錯誤大大減少,不僅開發效率得到提高,最重要的是代碼的質量得到了極大提升。
在本文中,主要介紹這兩個工具,并說明它們的工作方式。并且演示如何將TypeScript 和 Flow 集成到 React 應用程序中。
TypeScript
TypeScript 是微軟開發的一種編程語言。它是開源的,并得到了一個龐大而活躍的社區的支持。
TypeScript 是 JavaScript 的類型化超集,可編譯為純 JavaScript。
“類型化”一詞表示 TypeScript 要求程序員聲明給定變量的數據類型。
“超集”一詞表示 TypeScript 允許程序員使用 JavaScript 提供的所有功能,以及一些額外的功能 ,如接口,泛型,裝飾器等。
下圖展示了 TypeScript 運行方式的高級概述。編譯器接收 TypeScript 文件(.ts 或 .tsx),然后將它們“轉換”為可由瀏覽器運行的有效 JavaScript 代碼。
我們來看一些用 TypeScript 編寫的簡單代碼:
- function getName(person: IPerson):void{
- console.log(person);
- }
- interface IPerson{
- name: string
- age: number
- }
- getName({"name":"john",age:20});
- getName({age:23}) //Argument of type '{ age: number; }' is not assignable to parameter of type 'IPerson'.
正如我們在上面的代碼塊中看到的,我們聲明了一個函數,該函數接收一個具有兩個屬性的對象,分別是字符串和數字類型的名稱和年齡。調用該函數時,TypeScript 會檢查提供的對象的類型是否正確,如果類型不正確,就會像在調用第二個函數的時候代碼將無法編譯并拋出錯誤。
Flow
與 TypeScript 相比,Flow 并不是一種編程語言,它被叫做JavaScript 的靜態類型檢查器,類似于我們經常使用的ESLint,它是由 Facebook開發的。
我們可以通過向常規 JavaScript 文件添加特殊注釋來使用 Flow,指示我們期望的類型,或者我們可以讓工具推斷出期望的類型并在發現任何錯誤時警告我們。
我們來看看以下 Flow 官方文檔的案例:
- // @flow
- function square(n) {
- return n * n; // Error!
- }
- square("2");
注意到上面代碼的第一行了嗎?為了讓工具知道它必須檢查哪些文件,我們通過添加注釋 @flow在每個要包含在 Flow 監控過程中的文件中。
使用 Flow,您不必更改文件的擴展名,而是繼續在帶注釋的文件.js和.jsx文件中編寫普通的 JavaScript。
如果我們保留上面的代碼,JavaScript 引擎會因為注釋而拋出錯誤,因此,作為額外的步驟,我們必須在最后編譯代碼之前刪除所有注釋。
當然我們可以使用Babel 或者 flow-remove-types等工具來清除它們。
Flow 與 TypeScript 與 React 的集成
一個標準的 React 應用程序
創建 React 應用程序的最簡單方法是使用create-react-app工具。
我們將創建兩個相同的 React 應用程序,一個用于測試 TypeScript,另一個用于測試 Flow。
首先,讓我們通過創建一個沒有任何類型檢查的 React 應用程序來看看這個工具的實現:
- npx create-react-app demo-app
React啟用TypeScript
如果我們從頭開始,我們可以像這樣使用 –template 標志來創建一個支持 TypeScript 的 React 應用程序:
- npx create-react-app react-ts --template typescript
對于一個新項目這是一個最佳的辦法,如果我們想要在現有的項目中啟用react的話,我們需要做下面的操作。
- yarn add typescript @types/node @types/react @types/react-dom @types/jest
接下來,我們將現有的.js和.jsx文件重命名為.ts和.tsx。
重啟我們的開發服務器之后,你會發現項目目錄中多了一個tsconfig.json文件,這個文件是typescript的配置文件,你可以對它進行一些偏好配置。
然后我們創建一個React組件:
- import React from "react";
- interface Props{
- items: Item[]
- }
- export interface Item {
- id:number,
- name:string
- }
- function ItemList(props:Props){
- const listItems = props.items.map(item=>item.name);
- return listItems;
- }
- export default ItemList;
TypeScript 允許我們使用接口聲明我們期望的對象類型。
在這里,我們聲明了 Props 接口,它有一個屬性 item,一個 Item 類型的對象數組——另一個接口有兩個屬性,一個 number 類型的 id 和一個 string 類型的 name,兩者都是必需的。
然后,我們通過添加注解 props:Props 說我們的函數組件 ItemsList 的 props 參數是一個 Props 類型的對象。
讓我們ItemsList在我們的App.tsx文件中實現這個組件并聲明一個名為 items 的常量,就像一個包含虛擬對象的數組一樣,看看 TypeScript 是如何反應的:
您可以看到顯示了一個錯誤,指出 Item 必須包含 id 和 name 屬性。如果我們此時嘗試運行應用程序,TypeScript 可以避免我們產生錯誤。
現在讓我們刪除我們的項目 const 的類型,看看這個錯誤是否消失:即使我們沒有聲明項目 const 應該是 type Item[],TypeScript 也足夠聰明,可以發現在我們的ItemsList組件中使用它是不安全的。
現在讓我們通過向組件添加兩個適當的記錄來解決這個問題:
- const items: Item[] = [{ id: 1, name: "One" },{ id: 2, name: "Two" }];
我們現在看到應用程序編譯并成功執行:通過引入TypeScript,我們避免了運行潛在錯誤的代碼,同時還通過顯式聲明整個應用程序中使用的類型使代碼本身更具可讀性。
React啟用Flow
- yarn add flow-bin npm run flow init
然后我們創建和之前一樣的ItemsList組件。
- import React from 'react';
- function ItemsList(props) {
- const listItems = props.items.map(item => item.name);
- return (listItems);
- }
- export default ItemsList;// @flow
- import React from 'react';
- type Item = {
- id: number,
- name: string
- }
- type Props = {
- items: Item[]
- }
- function ItemsList(props: Props) {
- const listItems = props.items.map(item => item.name);
- return (listItems);
- }
- export default ItemsList;
運行yarn flow 會出現錯誤,接下來我們添加一些類型。
- // @flow
- import React from 'react';
- type Item = {
- id: number,
- name: string
- }
- type Props = {
- items: Item[]
- }
- function ItemsList(props: Props) {
- const listItems = props.items.map(item => item.name);
- return (listItems);
- }
- export default ItemsList;
重新運行yarn flow,將不會提示任何錯誤。
每次要使用 Flow 檢查文件時,我們都必須運行相同的命令。對于使用 VS Code 的用戶,可以使用Flow Language Support在每次保存后自動執行 Flow 檢查。其他 IDE 將具有等效功能,只需搜索即可找到與您的環境相關的實現。
TypeScript 與 Flow 的優缺點
TypeScript優點:
- 不僅僅是一個類型檢查器: TypeScript向 JavaScript添加了額外的數據結構,如Enums,來自其他語言的開發人員可能缺少這些數據結構。它還具有接口、裝飾器和其他使其更加健壯的功能——使開發人員能夠編寫極其全面的代碼。這些功能在大型和企業風格的項目中尤其強大。
- 由 Microsoft 開發: TypeScript 正在接收定期更新并將繼續發展。可以肯定地說,在快速發展的 JavaScript 生態系統中,TypeScript 的壽命將比大多數其他“趨勢”更長。
- 大型社區:TypeScript 擁有一個龐大而活躍的社區,他們愿意為它的開發做出貢獻,并通過回答他們的問題或編寫有用的教程來幫助他人。除了官方文檔 之外,您還可以找到大量有關 TypeScript 主題的非官方資源。
TypeScript缺點:
- 陡峭的學習曲線:TypeScript 一開始可能是嚴格且無情的,讓開發人員望而卻步。它比 Flow 更難和更復雜,因為它更健壯,并且被認為是一種編程語言(或至少是 JavaScript 的“超集”)。TypeScript 也感覺像是一種全有或全無的方法,這會使事情復雜化并減慢具有大量依賴項的大型項目的開發速度。
- 大量重復代碼:有人認為 TypeScript 沉淀了大量模板代碼,這會增加開發時間并使文件更難理解。在這種情況下,代碼極簡主義者可能更喜歡輕量級 Flow(或根本不進行類型檢查)。
Flow優點:
- 易用性: Flow 比 TypeScript 更寬容,可作為對 JavaScript 中靜態類型的更溫和的介紹。啟動和運行速度更快,而且由于其按文件選擇加入的方法,將 Flow 添加到現有項目中也可能更容易。
- 由 Facebook 開發:開發 React 的公司,因此您可以確定這兩種工具完全兼容并且可以一起使用。
Flow缺點:
- 更小的社區:Flow 擁有一個更小、更不活躍的社區,這意味著那些試圖學習如何使用它并調試可能出現的問題的人可用的資源更少。這也可能意味著它在支持和添加功能方面的未來比 TypeScript 更加不確定。
- 不那么健壯: Flow 可以很好地進行類型檢查,但僅此而已。TypeScript 可能更適合具有較長支持范圍的更多企業項目,同時考慮到開發人員可以在此類項目中使用其更高級的功能。Flow 可能是更精簡項目的更好選擇,或者作為將類型檢查引入現有項目的一種方式,而不會太痛苦。由您決定哪種工具最適合您的項目和環境。
結論
TypeScript 和 Flow 之間有明顯的區別。在功能方面,TypeScript 更健壯,而 Flow 只是一個類型檢查器。
盡管 Flow 是由 Facebook創建的,但是對于同公司開發的React框架來說,并沒有特別優待之處,畢竟它最初的目的就不是作為react的附屬工具,而是作為一個通用項目管理工具。
對于喜歡輕量級,喜歡快速上手的人來說,flow是一個不錯的選擇,你可以非常快速地入門并使用它。
而如果你在開發一個大型項目,那么typescript應該是你最佳的選擇,它龐大的社區讓它的發展異常迅速,主流的框架源碼都采用了typescript進行開發足以說明問題。