上帝視角看 TypeScript

lucifer發表於2020-08-04

TypeScript 的學習資料非常多,其中也不乏很多優秀的文章和教程。但是目前為止沒有一個我特別滿意的。原因有:

  • 它們大多數沒有一個清晰的主線,而是按照 API 組織章節的,內容在邏輯上比較零散。
  • 大多是“講是什麼,怎麼用“,而不是”講為什麼,講原理“。
  • 大多數內容比較枯燥,趣味性比較低。都是乾巴巴的文字,沒有圖片,缺乏能夠引起強烈共鳴的例子。

因此我的想法是做一套不同市面上大多數的 TypeScript 學習教程。以人類認知的角度思考問題,學習 TypeScript,通過通俗易懂的例子和圖片來幫助大家建立 TypeScript 世界觀。 而本篇文章則是這個系列的開篇。

系列安排:

  • 上帝視角看 TypeScript(就是本文)
  • TypeScript 型別系統
  • 什麼是 types?什麼是 @types?
  • 型別推導, 型別斷言與型別保護
  • 你不知道的 TypeScript 泛型(萬字長文,建議收藏)(已釋出)
  • TypeScript 練習題
  • TypeScript 配置檔案該怎麼寫?
  • TypeScript 是如何與 React,Vue,Webpack 整合的?
目錄將來可能會有所調整。

注意,我的系列文章基本不會講 API,因此需要你有一定的 TypeScript 使用基礎,推薦兩個學習資料。

結合這兩個資料和我的系列教程,掌握 TypeScript 指日可待。

接下來,我們通過幾個方面來從巨集觀的角度來看一下 TypeScript。

從輸入輸出上來看

如果我們把 Typescript 編譯器看成一個黑盒的話。其輸入則是使用 TypeScript 語法書寫的文字或者文字集合

(文字)

如果幾個文字有引用關係,比如 a.ts 依賴 foo.ts 和 bar.ts,其就是一個文字集合。

(文字集合)

輸出是編譯之後的 JS 檔案 和 .d.ts 的宣告檔案

其中 JS 是將來需要執行的檔案,而 .d.ts 宣告檔案則是 ts 檔案中的型別宣告,這個型別宣告就是你在 ts 檔案中宣告的型別和 TypeScript 型別推導系統推導的型別。當然你也可以自己寫 .d.ts 宣告檔案。

從功能上來看

從巨集觀的視角來看,TypeScript 的功能就是:

  • 提供了豐富的型別系統。

最簡單的就是 變數名:型別 = 值

const a: Number = 1;

除了這些基本型別,還提供了函式型別,複合型別等。

  • 提供了型別操作 API。TypeScript 不但提供內建型別,使用者也可以利用集合操作和泛型對型別操作從而生成新的型別。

  • 對每一種型別的屬性和方法都進行了定義。

比如 String 型別有 toString 方法,但是沒有 toFixed 方法,這就是 lib.d.ts 定義的。這樣我在 String 型別的變數上使用 toFixed 方法就會報錯,達到了“型別檢查”的作用。

小提示:lib.d.ts 的內容主要是一些變數宣告(如:window、document、math)和一些類似的介面宣告(如:Window、Document、Math)。 你可以通過 --noLib 來關閉這一功能
  • 提供了模組系統(module,namespace)。
  • 提供了更加方面的 API,比如 class(這在 ES6 class 出來之前尤其好用),裝飾器等。
  • 。。。

TypeScript 編譯器是如何工作的?

上面已經討論了 TypeScript 編譯器的輸入和輸出。那黑盒內部是怎麼工作呢?這裡我簡單介紹一下:

  • TypeScript 文字首先會被解析為 token 流。這個過程比較簡單,就是單純地按照分隔符去分割文字即可。

  • 接著 token 流會被轉換為 AST,也就是抽象語法樹

  • binder 則根據 AST 資訊生成 Symbol(TypeScript 中的一個資料結構)。拿上面的圖來說,就是 number 節點。
  • 當我們需要型別檢查的時候, checker 會根據前面生成的 AST 和 symbols 生成型別檢查結果
  • 當我們需要生成 JS 檔案的時候,emitter 同樣會根據前面生成的 AST 和 symbols 生成 JS 檔案

完整圖:

總結

總的來說,TypeScript 就是一門語言,和 Java,Python,C++ 等類似。只不過這門語言主要目標就是為了彌補 JavaScript 弱型別帶來的問題的。因此設計語言的出發點就是:

  • 靜態型別系統
  • 可以編譯成 JavaScript

因此 TypeScript 是一門最終編譯為 JavaScript 的語言(當然還有型別檔案)。既然是一門語言,就涉及詞法分析,語法分析等流程。由於相對 JavaScript 增加了很多功能, 其中最主要的就是型別系統。因此 TypeScript 的分析工作要比 JavaScript 更加複雜, 集中體現在 binder 和 checker 部分。

由於提供了靜態型別, 因此就需要提供一些內建型別給我們用,比如 number,string,Array 等。但是這並不能滿足我們的所有需求,我們需要自定義型別,因此有了 type,有了 interface 等。後來我們又發現自定義的型別重複程式碼太多, 要是型別也可以通過程式設計生成新的型別就好了,於是有了集合運算和泛型。

程式碼都放到一起不方便維護,要是可以放到不同檔案,需要用的時候組裝起來就好了,於是有了模組化。我用了別人的用 TypeScript 開發的庫,如果也能有型別校驗就好了,於是有了 types。

。。。

其實這些都是有因果關係的,如果你可以牢牢地掌握這些因果關係,那麼學起來還不是易如反掌?

相關閱讀

點關注,不迷路

大家也可以關注我的公眾號《腦洞前端》獲取更多更新鮮的前端硬核文章,帶你認識你不知道的前端。

知乎專欄【 Lucifer - 知乎

相關文章