別騙自己了,你不用 TypeScript 的理由站不住腳
自六年前誕生以來,TypeScript 已經走過了漫長的道路,並被一些領先的 Web 公司採用。你可以不使用 TypeScript,但你不使用 TypeScript 的理由有可能欠缺考慮。
在這篇文章中,我將介紹大家比較關心的與 TypeScript 相關的一些問題,比如學習曲線、工具、開發速度、可維護性和標準合規性問題。
1. 學習曲線過於陡峭
需要注意的是,TypeScript 並非一門全新的語言。CoffeeScript 和 Reason 分別將 JavaScript/">JavaScript 裝扮成其他程式語言的語法和語義——Ruby 和 OCaml,而 TypeScript 的目標則更為保守一些。
它只是在 JavaScript 之上添加了一個型別系統(TypeScript 是 JavaScript 的超集)。所以 TypeScript 的學習曲線比較平緩,從 JavaScript 切換到 TypeScript 並不像從一門語言切換到另一門語言那麼繁瑣。
這是 TypeScript 的一個程式碼片段:
複製程式碼
classGreeter{ greeting: string; constructor(message: string) { this.greeting = message; } greet() { return"Hello, "+this.greeting; } }
這是 JavaScript(ES6)的相同程式碼:
複製程式碼
classGreeter{ constructor(message) { this.greeting = message; } greet() { return"Hello, "+this.greeting; } }
正如 TypeScript 的共同作者 Anders Hejlsberg 說的那樣,“如果你瞭解 JavaScript,那麼差不多也就瞭解了 TypeScript”。
2. JS 是標準的,而 TypeScript 不是
當 TypeScript 於 2012 年問世時,帶來了類和模組等功能,直到 2015 年 ECMAScript 第 6 版(ES6 或 ES2015)最終確定時才成為“標準 JavaScript”。TypeScript 模組的原始實現偏離了 ES6,但在標準最終確定的同一年,它做了更新(保持向後相容性),以便與 ES6 規範保持一致。
現在,TypeScript 嚴格遵循 ECMAScript 規範,實現了大多數達到階段 3 的提議。也就是說,當你在編寫 TypeScript 時,實際上是在編寫符合標準的現代 JavaScript。經過ES3/ES5 轉換器的轉換,輸出的.js 檔案在舊版瀏覽器中也可以正常執行。
3. 它破壞了 JS 的動態特性
如果你已經使用過指令碼語言,那麼就應該體驗到它們所帶來的開發速度上的提升。你可以隨時自由處理資料結構,而無需事先宣告它們。然而,這種自由需要付出代價。動態型別的程式比靜態型別的程式更難以維護,因為流經程式的資料沒有編譯時驗證。
來看看這個簡單的 JavaScript 示例:
複製程式碼
functiongreeter(person){ return"Hello, "+ person.firstName +" "+ person.lastName; }
通過檢視程式碼,我們可以推斷 person 引數應該是具有 firstName 和 lastName 屬性的 Object。但在執行時我們不能保證一定會是這樣的。
專案越大,與型別相關的錯誤發生的機率就越高。
為了避免出現這類錯誤,可以使用執行時型別檢查和單元測試,如下所示:
複製程式碼
functiongreeter(person){ if(!person || !person.firstName || !person.lastName) { thrownewError('invalid arguments'); } return"Hello, "+ person.firstName +" "+ person.lastName; } // Jasmine spec: describe("greeter",function(){ it("returns greeting on valid input",function(){ expect( greeter({firstName:'James',lastName:'Hetfield'}) ).toEqual('Hello, James Hetfield'); }); it("throws on invalid input",function(){ expect(()=>greeter()).toThrowError('invalid arguments'); expect(()=>greeter(5)).toThrowError('invalid arguments'); expect(()=>greeter({firstName:'Jason'})).toThrowError('invalid arguments'); }); });
但這樣做有點累贅,而且開發人員需要負責驗證資料。我們是否可以為函式新增一個簡單的型別註解就可以搞定一切?
複製程式碼
interfacePerson{ firstName: string; lastName: string; } functiongreeter(person: Person){ return"Hello, "+ person.firstName +" "+ person.lastName; } // Jasmine spec: describe("greeter",function(){ it("returns greeting",function(){ expect( greeter({firstName:'James', lastName:'Hetfield'}) ).toEqual('Hello, James Hetfield'); }); });
上面的例子更加簡潔一些,讓我們可以專注於驗證測試中的業務邏輯。
TypeScript 通過採用結構化型別系統來體現 JavaScript 的動態特性,並且在型別推斷方面做得非常出色,這意味著你不必像 C# 或 Java 那樣明確表達型別。以下是使用我們使用 TypeScript 編寫的函式示例:
複製程式碼
letuser= { firstName:"James", lastName:"Hetfield"}; console.log(greeter(user));
這段程式碼可以成功編譯。請注意,我們並沒有明確地說明 user 變數實現了 Person 介面,也沒有明確定義擴充套件它的類。TypeScript 的設計目標之一不是為了建立一個“正確的型別系統”,而是“在正確性和生產力之間取得平衡”。
TypeScript 編譯器不會強制你宣告型別,型別安全的程度由你自己來決定。你甚至可以決定在專案的不同區域應用不同級別的型別安全嚴格程度。這種靈活性不是傳統的靜態型別語言可以提供的。
4. 它活不過 5 年
沒有人能夠知道 5 年後會出現什麼樣的語言、工具或框架,尤其是在 Web 領域。以下是 StackOverflow 部落格作者撰寫的有關 JavaScript 框架生命週期的內容:
JavaScript 框架似乎有兩個主要的階段。隨著框架在開發人員中變得越來越流行,先是有一個快速的上升期,然後隨著開發人員轉向新的開發技術,開始出現穩定下降。整個過程只會持續幾年時間。
我們都處在一個快速發展的行業,如果你和你的專案今天能夠從某些技術中受益,那麼就可以考慮使用它們。即使你在 1 至 2 年內會使用其他技術,你在這一兩年時間內獲得的好處也會加速你的專案開發,所以是值得的。
5. 它不是由社群驅動的
微軟於 2012 年釋出了 TypeScript。考慮到微軟公司本身及其開發平臺的聲譽,人們很容易認為 TypeScript 只是“適合.NET 開發人員口味的 JavaScript”。在當時,Visual Studio 是唯一支援該語言的 IDE,而這似乎進一步強化了這種看法。或者是因為該專案的原始碼最初發布在 CodePlex 上,CodePlex 是微軟執行的另一個類似 GitHub/">GitHub 的程式碼託管站點。
但從那以後,很多事情都發生了變化。TypeScript 團隊意識到,如果他們希望這門語言得到更廣泛的採用,他們需要通過提供高質量的工具和接受使用者反饋來更好地融入 Web 開發社群。他們不只是在真空中開發 TypeScript,而是完全接受了開放式開發的概念。
2014 年,TypeScript 的程式碼被遷移到 GitHub,並在 GitHub 上進行開發。他們邀請開源社群貢獻者加入,貢獻者可以記錄錯誤、記錄提案和提交拉取請求。問題跟蹤器中的問題會定期得到解決,每個提交通常會在幾天內通過評審。核心團隊已經發布了 TypeScript 的設計目標,這有助於專案在接受社群意見的同時堅持自己的使命。他們保持更新路線圖(現在大約每兩個月釋出一次新版本),並將重大變更記錄下來。
在撰寫本文時,所有主要的跨平臺 IDE 和文字編輯器(如 Eclipse、Webstorm、Emacs、Vim、Sublime、Atom、VS Code)都內建或通過外掛成功支援 TypeScript。核心團隊還投入了大量精力來建立型別定義檔案,以便與使用純 JavaScript 編寫的現有庫和框架實現互操作。另一件值得注意的事情是 TypeScript 提供了一組編譯器 API,可用於建立很多有價值的第三方語言工具。
考慮到所有這些因素以及 TypeScript 嚴重依賴 ECMAScript 的事實,我認為,這個專案其實是由社群驅動的,而且已經有好幾年時間了。以下是 EmberJS 聯合創始人 Tom Dale 在 2017 年對 TypeScript 的評論:
最重要的是,TypeScript 團隊的專業精神令人印象深刻。在目前怎樣的生態系統中,TypeScript 的持續迭代改進令人耳目一新。
6. 轉換現有專案的工作量太大
為了在專案中充分利用 TypeScript,你將不得不花時間宣告型別,並修復編譯器錯誤,這可能有點枯燥乏味。但是,TypeScript 作者在構建這門語言時也考慮到了 JavaScript 生態系統,併為在現有專案中採用 TypeScript 提供了平滑的過度。
根據官方遷移指南,只需通過 TypeScript 編譯器執行現有的 JavaScript 程式碼,就可以獲得 TypeScript 帶來的好處。編譯器將捕獲一些低階錯誤,例如函式末尾缺失 return 語句或者無法觸及的程式碼塊。然後,你可以逐個將.js 檔案重新命名為.ts,並解決編譯器捕獲到的問題。預設的編譯器選項非常寬鬆,當然你也可以啟用更嚴格的模式。你甚至可以在專案的不同部分使用不同的編譯器選項集,讓你的團隊可以按照自己的進度採用 TypeScript。最重要的是,從 JavaScript 到 TypeScript 有一條平穩的過渡路徑,不會阻礙整個公司的開發進度。
你可以選擇逐步將現有專案轉換為 TypeScript,或進行“大爆炸”式的轉換,或者只是在新專案中使用 TypeScript。還有像 ofollow,noindex">TypeWiz 這樣的社群專案可以自動將缺少的型別資訊新增到程式碼中。
7. 我使用的庫都是用 JavaScript 編寫的
為了實現與現有 JavaScript 程式碼的互操作性,TypeScript 還提供了 TypeScript 宣告檔案。例如,如果你使用的 JavaScript 庫匯出了一個叫作 camelize 的全域性函式,那麼它的 TypeScript 宣告將如下所示:
複製程式碼
declarefunctioncamelize(s:string):string;
將這個類宣告匯入專案後,TypeScript 就會知道這個函式的型別。
在釋出 TypeScript 的同一年,出現了另外一個社群儲存庫 DefinitelyTyped ——用於流行庫的宣告檔案。在撰寫本文時,它包含超過 5,000 個 JavaScript 包的宣告。使用這些宣告非常簡單,例如,如果你在專案中使用了 Jasmine 測試框架,只需執行:
複製程式碼
npminstall --save-dev @types/jasmine
然後編譯器會自動包含這些型別,你將在程式碼編輯器中獲得動態型別檢查和自動完成功能。你使用的所有或大多數軟體包應該已經為它們建立了高質量的型別宣告。Slack 的工程團隊分享了他們的經驗:
考慮到程式碼可維護性,我們要感謝 TypeScript 的生態系統。作為 React 和 Node/npm 生態系統的重度使用者,第三方庫的型別定義可用性是一個巨大的優勢。我們匯入的很多庫都已相容 TypeScript。如果定義不隨模組本身一起提供,可能可以在神奇的 DefinitelyTyped 專案中找到。例如,React 不附帶型別定義,但可以通過 npm install @types/react 來安裝,無需進一步配置。
結論
使用靜態型別檢查可以幫助你消除掉很多錯誤,TypeScript 是 Node/JavaScript 專案最流行的靜態型別解決方案。在一個相對較小或實驗性的專案中,使用 TypeScript 可能並不值得,但對於大型專案,其好處遠大於額外的開銷,這個已經得到谷歌、Slack、Asana、Ember 等公司的證實。希望本文為你提供了一個關於 TypeScript 的全新視角,也許是時候再給它一次機會了。
英文原文:
https://blog.logrocket.com/7-bad-excuses-for-not-using-typescript-dbf5e603a9a8