淺談Typescript前端體驗

語言: CN / TW / HK

前言

最近兩年,Typescript逐漸成為前端專案的標配,甚至出現了Typescript即將接管JS世界的段子。 大部分前端開發者也陸陸續續從ReactVueAngular開發生態中接觸到了TS,一時間關於Typescript的教程大量出現,不過大部分教程更關注Typescript 的型別系統。本文將對TS進行一個簡單的梳理總結,旨在讓 TS開發者換個角度瞭解Typescript。讀完本文後,我們應當能對Typescript 有以下認識:

  1. Typescript的設計初衷
  2. Typescript的兩大特性
  3. Typescript為我們帶來了什麼
  4. Typescript還為我們帶來了什麼
  5. Typescript如何更利於構建大型應用
  6. 關於Typescript的使用建議

Typescript的設計初衷

JavaScript的段子:動態一時爽,重構地雷場。

最近這些年,隨著硬體效能、前端自身快速發展等因素,前端應用程式的體量與複雜度直線上升。而在大型應用的開發過程中,JavaScript動態語言與弱型別的語言特性,隨著成員數量的增加、程式碼體量的增長、業務場景複雜度的上升,文件及單元測試的缺失等情況的出現,導致了以下問題:

  1. 型別錯誤多,bug率居高不下。
  2. 缺少文件、新成員理解應用邏輯困難。
  3. 維護成本高、可擴充套件性差的困境。

在軟體開發過程中,隨著需求的變化和系統規模的增大,我們的專案不可避免地會趨於複雜,最終造成了專案中後期進度緩慢的情形 。如何對軟體複雜度及其增長速率進行有效控制,便成為一個日益突出的問題。Typescript正是在這種情況下,應運而生的。

Typescript的維基百科詞條

TypeScript 起源於 Javascript 在微軟以及客戶中開發大型應用中遇到的缺點。處理複雜 JavaScript 程式碼帶來的挑戰使他們需要自定義工具來簡化元件開發流程。

TypeScript 開發者尋求一種不破壞現有標準相容性和跨平臺支援的解決方案。知道ECMAScript標準為未來基於類程式設計提供支援後, Typescript開發便基於此方案。這形成了包含一組新的語法擴充套件的一個JavaScript編譯器,一個基於此提案的超集,可將TypeScript語法編譯為常規的JavaScript。

TypeScript不僅包含JavaScript的語法,而且還提供了靜態型別檢查以及使用看起來像基於類的面向物件程式設計語法操作 Prototype。C#的首席架構師以及Delphi和Turbo Pascal的創始人安德斯·海爾斯伯格參與了TypeScript的開發。

Typescript的兩大特性

維基百科上關於Typescript的介紹,提到了兩個關鍵的詞:靜態型別檢查、面向物件。

前端在經過FlowTypescriptCoffeeScript等短暫的型別檢查之爭後。Typescript在開發速度、協作成本、維護成本上的出色表現,實踐過Typescript構建大型應用的團隊,幾乎是一邊倒的從JS轉向了TS。具有代表性的:Ant-designAngularVue-next從最初的JS版本切換到了TS版本。

有意思的是,為什麼React不使用Typescript?

靜態型別檢查

下圖即是TS的型別系統,市面上已經存在大量解讀型別系統的教程,在這裡我們不再贅述

img

面向物件

在2018年年初,我們使用Typescript重構React前端,很快我們與TS進入了短暫的蜜月期,低階的錯誤大幅減少。但隨後我們就發現,如果上述內容就是Typescript的全部內容,Typescript對我們來說就是一個玩具,一個高階玩具。

前面說過,隨著程式碼體量的增長、業務複雜度的上升,文件及單元測試的缺失,人員流動等因素的出現,功能理解、模組衝突、程式碼難以維護的問題,並沒有隨著靜態型別檢查的出現而大幅消失。

雖然逐漸沉澱出容器元件、展示元件、業務邏輯與UI分離等等模式,我們還是會遇到改一發而動全身的bug,新成員理解困難、老成員的模組各種衝突問題,逐漸我們感覺到Typescript似乎並沒有它宣稱的那樣強....

Typescript號稱適合構建大型應用,我們開始反思這句話是否正確。在github上我們注意到,vscode的原始碼便是通過Typecript編寫的。既然Typescript能搞定IDE編輯器這種複雜的應用,我們期望從vscode的原始碼中,找到解決方案。

img

img

剛開始我們對vscode中的這種寫法很困惑,並且對大量的implementsabstractprivate protect設計感到陌生。經過大量的面向Goole程式設計,我們逐漸注意到Typescript的第二個特點,面向物件:封裝、繼承、多型。

  • 封裝:隱藏資料和功能實現細節,避免被外部修改,而導致誤用。
  • 繼承:子類擁有父類的所有屬性和方法,從而實現了實現程式碼的複用。
  • 多型:同一個行為具有多個不同表現形式或形態的能力。

用一句話描述面向物件:將功能拆分為職責單一的功能、通過封裝將功能隔離開來,再通過組合的方式去構建大型應用。

面向物件是個比較大的領域,我們將通過下文中的的一個例子,簡單的講下對面向物件的三大特性

Typescript為我們帶了什麼

低階錯誤的查詢定位

rollbar 於 2018 年統計了前端專案中Top10 的錯誤型別

img

其中有 7 個是型別錯誤(TypeError),這對Typescript來說就是送分題。

閱讀程式碼能力的加持

vscode中有一些非常方便的程式碼閱讀技巧

  • 檢視用法 懸停: 讀取interface同時顯示註釋

img

  • 轉到定義 Ctrl + 單擊、轉到符號定義的原始碼 F12。
  • 窺視定義 Alt + F12:調出一個窺視視窗,顯示符號的定義。

img

  • 轉到參考 Shift + F12:顯示相似字元的所有參考。

img

智慧提示自動補全

IDE很早就有了自動補全功能,在有d.ts型別檔案後,可以自行編寫型別庫,供IDE識別,最具代表性的便是:www.typescriptlang.org/dt/search?s…

重構能力的增強

img

img

以上內容,我們可以總結為:

  • 型別錯誤的靜態檢查
  • 程式碼可閱讀性的提高
  • 編寫速度的加快
  • 可維護性的提高

Typescript還為我們帶來了什麼?

Typescript的靜態型別分析,目前是影響甚廣。而Typescript的面向物件,前端開發者普遍沒太大感受。與後端發展的時間相比,前端快速發展的時間太短,以至於前端整體並沒有沉澱出完整體系的設計模式、設計原則建模。藉助Typescript的特性,剛好使我們可以借鑑其它領域。

UML建模

UML主要使用圖形符號來表示軟體專案的設計,使用UML可以幫助專案團隊溝通、驗證功能的設計。

類圖:

img

時序圖:

img

使用者管理-時序圖

img

UML以圖形符號的形式,填補了一部分的設計文件與使用文件。

設計模式與設計原則

在Typescript出現之前,部分面向物件的設計模式也可以用JavaScript模擬出來,但因為缺少介面interface、訪問限定修飾符、抽象類幾個概念,面向物件中的封裝與多型在JavaScript中一直是一個難以理解、難以模擬的概念,而Typescript的出現恰好補上這缺失的一環。

最近幾年,在Typescript流行開來的同時,函數語言程式設計也隨著Redux等的流行而火熱起來。在這裡,我們無意爭論兩種程式設計模式孰優孰劣。我們需要的是保證應用構建的強壯與可維護。在使用Typescript的過程中,我們決定破界,去嘗試前端不熟悉的面向物件。 由於面向物件是個比較大的領域,我們在這裡不詳細介紹面向物件的內容,有興趣的同學可以通過底部設計模式的連結瞭解一下面向物件。

Typescript更利於構建大型應用

如果問Java、C#的開發者,靜態型別檢查有何意義?

標準答案是“靜態型別更有利於構建大型應用”。

Typescript與JavaScript在開發大型應用的進度對比,如下圖所示:

img

我們在前面的Typescript設計初衷中,提到在大型JavaScript專案中後期,經常我們面臨的3個問題:

  1. 型別錯誤多,bug率居高不下。

  2. 缺少文件、新成員理解應用邏輯困難。

  3. 維護成本高、可擴充套件性差的困境。

Typescript是如何解決上述問題的?

其一、靜態型別檢查可以儘早構建失敗。一旦編寫程式碼時發生型別不匹配,在編譯階段前、中階段均可發現。

其二、靜態型別對閱讀程式碼是友好的。針對大型應用,方法眾多,呼叫關係複雜,不可能每個函式都有人編寫細緻的文件,所以靜態型別就是非常重要的提示和約束。

其三、UML建模語言,彌補了部分設計文件與說明文件,同一套的設計模式,使得理解功能變得容易。

其四、藉助面向的設計思想,隱藏實現細節,加強功能的內聚性。控制介面暴露粒度,來降低功能間的耦合度,達到容易擴充套件的效果。

其五、靜態型別其配合IDE的重構功能,維護困難係數直線下降。

結合Tyepscript、React接觸面向物件OOP與函式程式設計FP,我們總結了如下體驗:

  1. 在應用設計層面,OOP有著一套完整的設計體系,可以應對模組可擴充套件性、業務的複雜性的挑戰。
  2. 在細節實現層面,不要為了OOP而OOP,OOP不是萬能的。
  3. 在處理資料流時,FP有著獨一無二的優勢。

關於使用Typescript的建議

我們的強烈建議是:Typescript是一種語言,包含兩部分內容:靜態型別檢查、面向物件。如果你已經嘗試了型別系統,並且已經熟悉了JavaScript的各種特性,不妨學習下面向物件,或許能更好的掌握Typescript這門語言。

在接觸面向物件之前的兩點提示:

  1. 設計原則、設計模式是一種程式設計正規化,是跨語言、跨框架的。
  2. 強型別的語言特性,帶來了一種新思維習慣。

結語

通過前文所述,我們應該知道:

  • Typescript的設計初衷是為了應對大型應用中JavaScript的複雜性而設計的。
  • Typescript的兩大特性:靜態型別檢查、面向物件。
  • Typescript作為一種強型別語言,不僅有靜態型別系統,更我們帶來了一套完整的控制功能複雜度的技術體系。
  • 如果你是一名中高階前端,建議在擁抱函數語言程式設計的同時,嘗試跨界學習下面向物件程式設計。