上帝視角看 TypeScript
點(diǎn)擊藍(lán)色“腦洞前端”關(guān)注我喲
加個(gè)“星標(biāo)”,帶你揭開(kāi)大前端的神秘面紗!
?這是腦洞前端第「99」篇原創(chuàng)文章
TypeScript 的學(xué)習(xí)資料非常多,其中也不乏很多優(yōu)秀的文章和教程。但是目前為止沒(méi)有一個(gè)我特別滿意的。原因有:
它們大多數(shù)沒(méi)有一個(gè)清晰的主線,而是按照 API 組織章節(jié)的,內(nèi)容在邏輯上比較零散。 大多是“講是什么,怎么用“,而不是”講為什么,講原理“。 大多數(shù)內(nèi)容比較枯燥,趣味性比較低。都是干巴巴的文字,沒(méi)有圖片,缺乏能夠引起強(qiáng)烈共鳴的例子。
因此我的想法是做一套不同市面上大多數(shù)的 TypeScript 學(xué)習(xí)教程。以人類認(rèn)知的角度思考問(wèn)題,學(xué)習(xí) TypeScript,通過(guò)通俗易懂的例子和圖片來(lái)幫助大家建立 TypeScript 世界觀。而本篇文章則是這個(gè)系列的開(kāi)篇。
系列安排:
上帝視角看 TypeScript(就是本文) TypeScript 類型系統(tǒng) 什么是 types?什么是 @types? 類型推導(dǎo), 類型斷言與類型保護(hù) 你不知道的 TypeScript 泛型(萬(wàn)字長(zhǎng)文,建議收藏)(已發(fā)布) TypeScript 練習(xí)題 TypeScript 配置文件該怎么寫? TypeScript 是如何與 React,Vue,Webpack 集成的?
目錄將來(lái)可能會(huì)有所調(diào)整。
注意,我的系列文章基本不會(huì)講 API,因此需要你有一定的 TypeScript 使用基礎(chǔ),推薦兩個(gè)學(xué)習(xí)資料。
深入理解 TypeScript??https://jkchao.github.io/typescript-book-chinese/ 官方文檔?https://www.typescriptlang.org/docs/home
結(jié)合這兩個(gè)資料和我的系列教程,掌握 TypeScript 指日可待。
接下來(lái),我們通過(guò)幾個(gè)方面來(lái)從宏觀的角度來(lái)看一下 TypeScript。
從輸入輸出上來(lái)看
如果我們把 Typescript 編譯器看成一個(gè)黑盒的話。其輸入則是使用 TypeScript 語(yǔ)法書寫的文本或者文本集合。

(文本)
如果幾個(gè)文本有引用關(guān)系,比如 a.ts 依賴 foo.ts 和 bar.ts,其就是一個(gè)文本集合。

(文本集合)
輸出是編譯之后的 JS 文件 和 .d.ts 的聲明文件。

其中 JS 是將來(lái)需要運(yùn)行的文件,而 .d.ts 聲明文件則是 ts 文件中的類型聲明,這個(gè)類型聲明就是你在 ts 文件中聲明的類型和 TypeScript 類型推導(dǎo)系統(tǒng)推導(dǎo)的類型。當(dāng)然你也可以自己寫 .d.ts 聲明文件。
從功能上來(lái)看
從宏觀的視角來(lái)看,TypeScript 的功能就是:
提供了豐富的類型系統(tǒng)。
最簡(jiǎn)單的就是 變量名:類型 = 值
const?a:?Number?=?1;
除了這些基本類型,還提供了函數(shù)類型,復(fù)合類型等。
提供了類型操作 API。TypeScript 不但提供內(nèi)置類型,用戶也可以利用集合操作和泛型對(duì)類型操作從而生成新的類型。

對(duì)每一種類型的屬性和方法都進(jìn)行了定義。
比如 String 類型有 toString 方法,但是沒(méi)有 toFixed 方法,這就是 lib.d.ts 定義的。這樣我在 String 類型的變量上使用 toFixed 方法就會(huì)報(bào)錯(cuò),達(dá)到了“類型檢查”的作用。
小提示:lib.d.ts 的內(nèi)容主要是一些變量聲明(如:window、document、math)和一些類似的接口聲明(如:Window、Document、Math)。你可以通過(guò) --noLib 來(lái)關(guān)閉這一功能
提供了模塊系統(tǒng)(module,namespace)。 提供了更加方面的 API,比如 class(這在 ES6 class 出來(lái)之前尤其好用),裝飾器等。 。。。
TypeScript 編譯器是如何工作的?
上面已經(jīng)討論了 TypeScript 編譯器的輸入和輸出。那黑盒內(nèi)部是怎么工作呢?這里我簡(jiǎn)單介紹一下:

TypeScript 文本首先會(huì)被解析為 token 流。這個(gè)過(guò)程比較簡(jiǎn)單,就是單純地按照分隔符去分割文本即可。

接著 token 流會(huì)被轉(zhuǎn)換為 AST,也就是抽象語(yǔ)法樹(shù)。

binder 則根據(jù) AST 信息生成 Symbol(TypeScript 中的一個(gè)數(shù)據(jù)結(jié)構(gòu))。拿上面的圖來(lái)說(shuō),就是 number 節(jié)點(diǎn)。 當(dāng)我們需要類型檢查的時(shí)候, checker 會(huì)根據(jù)前面生成的 AST 和 symbols 生成類型檢查結(jié)果。 當(dāng)我們需要生成 JS 文件的時(shí)候,emitter 同樣會(huì)根據(jù)前面生成的 AST 和 symbols 生成 JS 文件。
完整圖:

總結(jié)
總的來(lái)說(shuō),TypeScript 就是一門語(yǔ)言,和 Java,Python,C++ 等類似。只不過(guò)這門語(yǔ)言主要目標(biāo)就是為了彌補(bǔ) JavaScript 弱類型帶來(lái)的問(wèn)題的。因此設(shè)計(jì)語(yǔ)言的出發(fā)點(diǎn)就是:
靜態(tài)類型系統(tǒng) 可以編譯成 JavaScript
因此 TypeScript 是一門最終編譯為 JavaScript 的語(yǔ)言(當(dāng)然還有類型文件)。既然是一門語(yǔ)言,就涉及詞法分析,語(yǔ)法分析等流程。由于相對(duì) JavaScript 增加了很多功能, 其中最主要的就是類型系統(tǒng)。因此 TypeScript 的分析工作要比 JavaScript 更加復(fù)雜, 集中體現(xiàn)在 binder 和 checker 部分。
由于提供了靜態(tài)類型, 因此就需要提供一些內(nèi)置類型給我們用,比如 number,string,Array 等。但是這并不能滿足我們的所有需求,我們需要自定義類型,因此有了 type,有了 interface 等。后來(lái)我們又發(fā)現(xiàn)自定義的類型重復(fù)代碼太多, 要是類型也可以通過(guò)編程生成新的類型就好了,于是有了集合運(yùn)算和泛型。
代碼都放到一起不方便維護(hù),要是可以放到不同文件,需要用的時(shí)候組裝起來(lái)就好了,于是有了模塊化。我用了別人的用 TypeScript 開(kāi)發(fā)的庫(kù),如果也能有類型校驗(yàn)就好了,于是有了 types。
。。。
其實(shí)這些都是有因果關(guān)系的,如果你可以牢牢地掌握這些因果關(guān)系,那么學(xué)起來(lái)還不是易如反掌?
相關(guān)閱讀
TypeScript 編譯原理?https://jkchao.github.io/typescript-book-chinese/compiler/overview.html Bring your own TypeScript with more internal definitions?https://github.com/basarat/byots Compiler Internals?https://github.com/microsoft/TypeScript/wiki/Compiler-Internals TypeScript 編譯器是用 TypeScript 寫的,那是先有編譯器還是 TS?https://github.com/azl397985856/fe-interview/issues/135
推薦閱讀
1、你不知道的前端異常處理(萬(wàn)字長(zhǎng)文,建議收藏)
2、你不知道的 TypeScript 泛型(萬(wàn)字長(zhǎng)文,建議收藏)
3、想寫出效率更高的正則表達(dá)式?試試固化分組和占有優(yōu)先匹配吧
4、immutablejs 是如何優(yōu)化我們的代碼的?
5、或許是一本可以徹底改變你刷 LeetCode 效率的題解書
6、想去力扣當(dāng)前端,TypeScript 需要掌握到什么程度?
?關(guān)注加加,星標(biāo)加加~
?
如果覺(jué)得文章不錯(cuò),幫忙點(diǎn)個(gè)在看唄
