項目中使用 TypeScript 的一些感悟

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 只是一個工具,什麼時候用它,怎麼用它,還是取決於具體的場合。一味地尬吹或者否認其他的東西,只能說明思想還是太狹隘了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章