專案中使用 TypeScript 的一些感悟

jrainlau發表於2019-07-07

image

上週釋出了一款名為 Smartour 的工具,是完全採用 TypeScript (以下簡稱 ts)來開發的。拋開以前做業務的時候的不完全使用,這次實踐可以算是我第一次真正意義上的使用 ts。由於寫法上的不同,以及對不熟悉事物的新鮮感,在這次專案開發的過程中著實有著許多感悟,於是打算寫篇小東西好好記錄下來。

TS 能讓人養成“先思考後動手”的好習慣

在以往的開發過程中,我的習慣總是“先想好一個大概,然後邊做邊想再邊改”。這樣的好處是動作比較快,順利的時候效率會很高,但更多的時候是不斷地推翻自己先前的想法,相信不少的人也有跟我類似的體會。

而使用 ts,可以在一定程度上減少這個問題。眾所周知 ts 是強型別的語言,這也意味著它能有效制約開發者在開發過程中“隨心所欲”的程度。就以定義一個函式的引數為例,可以看看我在寫 js 和 ts 的思考方式上有什麼不同。

寫 js 的時候,我的思考過程是這樣的。

  1. 首先這個引數是一個物件,這個物件的屬性 el 是一個 css 選擇器;而物件的屬性 keyNodes 是一個陣列,裡面的元素是一系列的 keyNode
  2. 這個所謂的 keyNode 也是一個物件,它也包含了一個 css 選擇器屬性 el,以及一個繫結在 dom 元素上的事件引數 event
  3. 我會把這個引數物件以註釋的形式寫下來,以便記住它的具體定義。
/**
{
    el: '#demo-id',
    keyNodes: [{
      el: '.item-1',
      event (e) { console.log(e) }
    }]
}
 */
  1. 以後任何地方要用到這個引數,我都要手動保證引數的結構要和這個註釋保持一致。

而換成 ts 的寫法以後,我的思路是這樣的:

  1. 首先這個引數是一個物件,這個物件的屬性 el 是一個 css 選擇器;而物件的屬性 keyNodes 是一個陣列,裡面的元素是一系列的 keyNode
  2. 然後我會通過 interface 把它給定義好:
interface HightlightElement {
    el: string,
    keyNodes: Array<KeyNode>
}
interface KeyNode {
    el: string,
    event: EventListener
}
  1. 在需要用到這個引數的時候,只需要在定義形參的時候傳入這個 interface 即可。萬一引數結構或內容的型別有誤,VScode 編輯器都會立刻給予提示,省去了手動檢查的麻煩。
someFunction (param: HightlightElement) { ... }

可以看到,在寫 js 的時候更多的是“自己和自己約定,自己判斷是否遵守了約定”,而 ts 則是“自己和自己約定以後,由第三方(編輯器)去判斷是否遵守了約定”。這樣的好處是除了老生常談的減少錯誤之外,更多的則是對思維上的良性約束。這種良性約束能夠讓我們在思考的階段就定義好接下來要做的一系列事情,在操作的過程中如果發現任何問題也能夠在第一時間溯源回最初思考的起點,排查問題的時候會更加高效。

TS 擁有自成文件的特性

在寫 js 的時候,我們依賴註釋去判斷某個變數或引數的型別、結構和作用。如果沒有了註釋,只能通過閱讀原始碼和不斷除錯去搞清楚當中的細節。許多人在接手他人專案的時候都會有這麼一個經歷:“為什麼不寫註釋!這個函式寫的啥!這引數又是啥!”沒有註釋的 js 程式碼是讓人崩潰的,但是寫註釋不僅需要時間,更考驗一個人的概括能力。說了等於沒說甚至誤導性的註釋,也是足夠讓人崩潰。

在 ts 中,除了註釋以外我們還有另外一個選擇,就是檢視某個變數或引數所對應的 interface 介面定義。在 interface 中我們可以很直觀地看到引數的結構,內部屬性的型別,是否為可選等詳細資訊。再加上VScode 的智慧提示及跳轉,不管是檢視他人的程式碼還是維護一個歷史專案,都能更加方便和規範——畢竟寫介面往往比寫註釋要順手,看介面往往比猜程式碼要穩妥。

說到自成文件的特性,我也聯想到了另外一個熱門技術 GraphQL。藉助 GraphQL 社群配套的一系列工具,呼叫方在呼叫介面的時候就能直接讀到介面的標準定義;而介面的開發者也不需要額外編寫文件,在定義介面的時候其實就相當於把文件也寫好了。

自成文件的特性對於多人維護的專案來說是非常有用的,它能夠大大降低專案當中溝通和理解的成本。但是這句話也有一個前提,就是開發者要遵守併合理工具當中的約束規範,如果一個介面的任何引數型別都是 any ,那麼也就失去了使用 ts 的意義。

TS 能夠降低搭建環境的時間成本

為了同時使用 js 新穎的特性以及相容陳舊的瀏覽器,我們往往會藉助一系列的工具去搭建一套開發環境。也許我們已經習慣了 webpack + babel 的開發方式,可是又有誰能夠保證自己在不看文件的情況下能夠自己去搭一套呢?且不說這些工具各有著複雜的文件,就算好不容易把環境搭好了,還會發現有著更多“最佳實踐”。改來改去花了一天時間,才終於算是完成。

作為 js 的超集,我們可以在 ts 中放心使用 js 的各種高階能力。由於自帶命令列工具,我們不再需要去研究 babel 或者各種 preset-env 外掛,只需要指定需要構建的版本,ts 命令列工具就會自動為我們生成對應版本的 js。

當然這並不是說有了 ts 就能夠完全拋棄構建工具了,在構建複雜應用(如包含各種靜態資源,跨格式檔案引用)場景的情況下還是離不開構建工具的,且在未來很長一段時間都會維持這種狀況。但是秉承著“多一事不如少一事”的原則,只要能夠減少哪怕是一個工具的使用,對開發者來說都是有好處的,畢竟我們都期待著某一個能夠只管程式碼不管環境的日子。

尾聲

由於不是 ts 的資深玩家,以上的碎碎念都是作為一個初學者個人的新鮮感。在工作的這些日子裡,也深刻體會到永遠沒有百分百理想化的東西。ts 固然是好,但也需要辯證地看待它。我們是否真的需要 ts?它是否真的能夠提高我們的生產力?它是否真的如他人描述般理想?這些問題都需要經過實踐才能回答。說到底 ts 只是一個工具,什麼時候用它,怎麼用它,還是取決於具體的場合。一味地尬吹或者否認其他的東西,只能說明思想還是太狹隘了。

相關文章