2019年,越來越多的知名前端開源項目選擇使用 TypeScript 做為其新版本的開發(fā)語言,TypeScript 的社區(qū)支持也日趨完善,
VS Code + TypeScript 的組合拳讓不少原本持懷疑,甚至抵制態(tài)度的前端開發(fā)者們不禁喊出“真香!”。
然而,無論是在大公司還是中小型公司中,依舊有相當(dāng)多的前端工程師對TS有著理解偏差。TS的官方文檔也過于技術(shù)性,并沒有對TS的誕生原因,所要解決的問題等做細(xì)致的解釋。
所以本次演講并不會關(guān)注太多TS本身的語法,高級用法這類話題,因為在這些方面,官方文檔是更好的資料來源。而希望聽眾在分享結(jié)束后,能更明白TS成功的背后,
究竟是解決了哪些問題?
它的核心是什么?
它的與眾不同之處在哪?
團(tuán)隊是否該引入TS以及如何引入?
????????????????????????????????????????????????????????????????????????????????????????Part 1?如何定義TypeScript

TS官網(wǎng)下的定義為“JavaScript that scales”,這句話如果翻譯為中文不是一件簡單的事。Scales意味著“規(guī)模擴(kuò)大”。而對應(yīng)的中文官網(wǎng)直接翻譯成“JavaScript的超集",顯然是有點文不對題的。
然而,這卻恰好從兩個不同的層面解釋了什么是TypeScript。
英文版告訴你,TS與JS的能力區(qū)分在哪:即TS更能適應(yīng)項目規(guī)模不斷擴(kuò)大的場景。
中文版告訴你,TS的本質(zhì)是什么:即它是一種具有類型系統(tǒng)的JS的超集。
1.2 不僅僅是一門語言

如果你覺得定義本身比較空洞,想要更簡單直接的了解TS是什么,不如看看它帶來了什么。
作為一門語言本身來說,首先帶來的是類型安全,可以類比java,c++。
另外,TS包含一個編譯器,通過來你可以使用最新最穩(wěn)定的JS特性,功能類似babel。
最后,最核心的部分,由于ts帶來類型,所以你的工具,IDE可以更容易的理解你的代碼。從而可以創(chuàng)造很多工具,來幫助你更高效的寫高質(zhì)量的代碼。
所以總結(jié)起來TS不僅僅是一門語言,而是生產(chǎn)力工具。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?Part 2 JS世界的傲慢與偏見
說到TS,就不得不提JS,JS作為一門非常有爭議的語言,發(fā)展到今天成為當(dāng)下最流行的語言的過程是非常戲劇性的。
有很多必然,也有很多偶然。前端社區(qū)有關(guān)js的爭論,也一天沒有消停過,那我們就來看一下js的世界里有哪些有趣的話題。
2.1 開發(fā)者的偏見

在過去,很多人把JS當(dāng)做是一個玩具語言。我們也會發(fā)現(xiàn)在某些場景,使用JS的人員并不一定是開發(fā)者(譬如早期qq空間通過腳本裝飾頁面)。更可以毫不夸張的說,很多開發(fā)者覺得,JS是一門,等真正需要用到的時候,再去隨意學(xué)學(xué),就能上手的語言。種種原因?qū)е铝薐S在很多時候被濫用。
2.1.1 偏見的背后

當(dāng)然JS本身的確是存在非常多的問題,尤其在早期的時候。沒有模塊、class、類型。還有一堆為人所詬病的語言設(shè)計,null、undefined、NaN等等。
2.1.2 開發(fā)者是如何應(yīng)對JS的種種問題的

雖然JS有諸多糟粕,但是在瀏覽器里,你沒辦法擺脫他。“聰明”的開發(fā)者們想出了“用我喜歡的語言來編譯生成JS”這樣的點子,把JS僅僅當(dāng)作媒介語言。你幾乎可以找到任何語言的版本,這其中有像Google的GWT,微軟的Script#都是被大規(guī)模在正式環(huán)境中應(yīng)用的產(chǎn)品。
慢慢的,一些“更聰明”的開發(fā)者覺得這種方式有點不倫不類,不如徹底一點,干脆發(fā)明一些新的語言來取代JS。這里面最為出名的就是Google的Dart與CoffeeScript。
2.1.3 取代的結(jié)果如何

在google trend中,如果把CoffeeScript、Dart、TypeScript一起搜索。可以看到,從2014年至今,CoffeeScript與Dart基本沒掀起任何波浪,而TS迎頭直上。
2.1.4 從失敗中吸取教訓(xùn)

為什么TS可以,而其他這些語言卻沒法成為主流呢?這其中主要有三個原因:
1. 沒有嚴(yán)格遵從ECMAScript的規(guī)范。語法層面他們和JS是完全割裂的。譬如CoffeeScript用的是接近于ruby的語法,當(dāng)使用這樣的語言的時候,你會感覺你是完全在學(xué)一門新語言。有一定的學(xué)習(xí)成本。在ECMAScript規(guī)范不斷演進(jìn)的情形下,這類語言的語法就會越來越成為累贅。
2. 性能問題。這在早期的時候更為明顯。圖中的一段Dart代碼,在用Dart的編譯器轉(zhuǎn)化為JS后,不做任何優(yōu)化的情況下,居然產(chǎn)生了10000多行代碼。這顯然是難以接受的。
3. 生成代碼的可讀性差,沒有辦法回退。畢竟只是把JS做為媒介語言,JS的可讀性不是這類語言的考量。這也意味著一旦項目啟動,就沒法很輕松的回退回原生JS。
2.2 來自開發(fā)者的傲慢
2.2.1 坊間流言

基于種種原因,開發(fā)者們越來越傾向于寫原生JS。HTML5,Nodejs,還有像Angular,React,Vue這樣優(yōu)秀的前端框架又把JS的使用推向另一個高度。每一個JS開發(fā)者都無比的振奮。于是,漸漸的,我們又聽到了另外一種聲音。
1. 凡是可以用JS來寫的應(yīng)用,最終都會用JS來寫--At Woods定律。
2. js是最好的語言,反正你們饒了一圈最后都會回來。
3. 微軟出的東西,能行么?

目前在github上熱度前十的項目中,微軟直接占了兩席。而排在第八位的,也是社區(qū)中TS的周邊產(chǎn)物。

StackOverFlow的報告,在程序員最喜歡的語言中,TS與Python目前并列第二,僅次于Rust。

Npm包的開發(fā)者中,高達(dá)62%的開發(fā)者在使用TS。
從這些數(shù)字中可以很明顯的看出,當(dāng)下TS已經(jīng)取得了相當(dāng)驚人的成就。
2.2.3 為何TS會取得如此成功

TS會取得如此成功主要有5個原因:
1. 對類型安全的訴求。
無論在瀏覽器還是服務(wù)端,前端項目規(guī)模越來越大,越來越復(fù)雜。而規(guī)模越大,對靜態(tài)類型語言的訴求就越強(qiáng)烈。
2. 嚴(yán)格遵守ECMAScript規(guī)范。
與那些把JS當(dāng)作媒介語言的語言是不同的。TS選擇改進(jìn)了JS,而不是取代它。學(xué)習(xí)ts語法并不會增加額外成本。
3. 采用Structural Typing而不是Nominal Typing。
面向?qū)ο蟮恼Z言,一般使用nominal typing(C++, Java, Swift),而函數(shù)式語言更習(xí)慣使用Structural Typing(OCaml, Haskell, Elm)。JS里面,你即可以使用面向?qū)ο?,又可以使用函?shù)式。但js的開發(fā)者通常更傾向于使用函數(shù)式編程。這種情況下,TS選擇了使用結(jié)構(gòu)類型,也更符合js開發(fā)者的編程習(xí)慣。
4. 強(qiáng)大的開發(fā)工具。
正如我前面提到的,通過工具提高生產(chǎn)力才是TS的核心目標(biāo)。TS本身提供了非常棒的工具支持,他的TS Server機(jī)制是非常有創(chuàng)造性的(后面會詳述)。
5. Open Source, Open Development。
TS是以100%的開放開發(fā)的方式來運營的。也就是說有關(guān)與ts的一切,都是對開發(fā)者100%透明的。在過去,當(dāng)你給一門語言提一個bug的之后,可能等一兩年才會出新版本,而到那個時候你才會發(fā)現(xiàn),你提的bug可能根本沒被修復(fù)。通過TS的roadmap你可以清晰的看到具體哪些bug會被修復(fù),哪些feature會被新增,以及所有關(guān)于這些技術(shù)點的討論。這樣拉近了核心開發(fā)團(tuán)隊與使用者的距離,讓TS的社區(qū)非常的活躍。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Part3 騰訊在線教育選擇TS的四個理由
3.1 理由一:更少的Bug
3.1.1 研究與實踐

要具體的量化這個減少bug的百分比,不是一件容易的事。
不過倫敦大學(xué)與微軟研究院的一些學(xué)者,發(fā)表了一篇相當(dāng)有影響力的論文。文中指出,15%的github 公開bug,是可以通過Typescript來規(guī)避的。而根據(jù)在線教育TS使用的實際經(jīng)驗,數(shù)據(jù)統(tǒng)計,我們發(fā)現(xiàn)超過30%的bug都可以通過類型安全來規(guī)避。
3.1.2 為什么達(dá)到30%

業(yè)務(wù)中的通常bug可以被分為兩類,一類是類型錯誤(type error)引發(fā)的bug,這部分錯誤中的大多數(shù)是可以通過ts來避免的。
另一類是實現(xiàn)錯誤(spec error)引發(fā)的bug,比如對需求沒有理解透徹,導(dǎo)致做出來的功能不符合預(yù)期,或者有邏輯bug。所以TS能減少的具體的bug比例數(shù)字,與類型錯誤引起的bug在項目總體中的比例有關(guān)。
3.2 理由二:提高生產(chǎn)力
3.2.1 如何提高生產(chǎn)力

靜態(tài)類型,除了保證了類型安全。更重要的是,讓你的電腦、軟件可以更懂你的代碼涵義。從而使得制作更好的生產(chǎn)力工具成為可能。生產(chǎn)力工具的提升,讓開發(fā)者可以更加愉悅的寫代碼。從而最終提高生產(chǎn)力。
3.2.2 常用功能

此處主要通過demo展示帶TS在VS Code中一些能力。代碼提示、引用查詢、自動import、代碼即文檔等。
3.2.3 生產(chǎn)力提高的背后
工具能力的提升只是在表面。相信很多人會有這樣的疑問:沒錯在VS Code里寫TS很方便。但是這種不都是IDE本身提供的嗎?

事實上,這些能力其實是由TS本身提供的:
1. 與其他編譯器不同,TS的編譯器不是一個黑盒,而是完全對外開放的。
2. TS的編譯器架構(gòu),包括了底層了核心Ts編譯器,語言服務(wù),并且通過ts server把他所支持的功能都通過api暴露出來。
3. 第三方的工具就可以通過這個api來直接使用ts語言服務(wù)的各種功能。
4. 通過這種方式,其他的ide,工具,也可以快速的集成TS的相關(guān)能力。這也是為什么即使你使用webStorm也可以獲得與VS Code類似的TS開發(fā)體驗。
3.3 理由三:端到端的類型安全
3.3.1 使用TS之前

圖中是一個比較常見的架構(gòu)。我們有運行在瀏覽器中的頁面代碼,它與中間的接入層nodejs服務(wù)進(jìn)行通信,在后臺我們還有一個C++服務(wù),它nodejs服務(wù)之間用protobuf, 以rpc的形式來進(jìn)行通信。
這個時候,一旦后臺的協(xié)議發(fā)生更改,是一件非常棘手的事情,因為這里面沒有任何類型追蹤,我們需要在前端瀏覽器代碼和nodejs代碼中全局搜索對應(yīng)的字段來修改,非常容易改錯改漏。
3.3.2 使用TS之后

通過protobuf的TS插件,將請求、返回結(jié)構(gòu),方法等全都轉(zhuǎn)換為TS。并且在頁面代碼與node服務(wù)代碼中進(jìn)行共享。

當(dāng)proto協(xié)議文件發(fā)生更改的時候,只需要重新生成新的TS類型文件,無論是頁面代碼,還是node服務(wù)代碼都會自動報錯,提示開發(fā)者去做對應(yīng)字段的修改。
3.4 理由四:強(qiáng)大的社區(qū)支持
3.4.1 第三方庫

因為現(xiàn)如今任何一個前端項目都會引入大量的第三方庫。對于這些第三方庫,如果作者本身沒有提供類型定義怎么辦呢?
社區(qū)早就有了非常成熟解決方案,DenitelyTyped這個倉庫目前是github排名第八的項目,有著超過10000名的代碼貢獻(xiàn)者,這里面有超過5000個前端庫的類型定義。基本上你會用的,都已提供了類型定義。
3.4.2 框架反哺

我們也發(fā)現(xiàn)越來越多的,非常有影響力的前端框架的新版本都開始用ts來進(jìn)行重寫了。Angular 2, Vue3等等。
而這些社區(qū)中的開發(fā)者,都是開源社區(qū)最活躍的參與者,他們會將開發(fā)過程中遇到的ts的一些問題,通過PR或者反饋的方式再反哺到ts社區(qū)中,讓ts的生態(tài)越來越好。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?Part4 團(tuán)隊TS引入策略
4.1 確定是否有必要引入

在正式引入之前,第一點還是需要明確一下,你的團(tuán)隊的具體需求。
1.你的項目規(guī)模是怎樣的?當(dāng)然規(guī)模越大TS的幫助也就越大。
2.項目是由存在多人合作或者經(jīng)常有新人員加入呢?如果回答是yes,TS的使用,可以讓你的代碼更規(guī)范,讓新人更快速的熟悉代碼。
3.是否需要長期維護(hù)?TS100%可以讓你的項目結(jié)構(gòu)更健康,更容易的去重構(gòu)。
4.2 定點試驗

1.成立實驗小組,讓這部分人員先行,在項目中進(jìn)行試點。
2. 這段時間內(nèi),要定期的對這部分人員進(jìn)行問卷調(diào)查,看看他們的滿意度。
3. 將遇到的疑問,譬如像第三方依賴怎么辦之類的問題,梳理成FAQ,以便后續(xù)做更大范圍的宣導(dǎo)。
4.3 構(gòu)建遷移

構(gòu)建遷移,其實非常的簡單。通常我們需要處理的就是babel和webpack。這兩者現(xiàn)在都利用了TS 的語言服務(wù)能力。
1. 如果你的代碼需要用babel轉(zhuǎn)換,你可以直接加上babel-ts插件,這樣你編譯出來的代碼就自動會去除掉ts的類型,其他的功能還是走babel的轉(zhuǎn)化邏輯。
2. 更多的時候,你會選擇第二種,直接放棄掉babel,使用webpack的ts-loader直接對ts進(jìn)行編譯。
4.3.1 構(gòu)建優(yōu)化

TS3.0增加了project reference功能。
1. 你只需要在子文件夾里面,分別建一個新的tsconfg文件。在要引用的tsconfig中加上reference引用到另一個項目。在被引用的文件夾的tsconfig中增加composite為true。
2. 通過這樣的配置,當(dāng)ts在做類型檢查的時候,只會檢查當(dāng)面項目的ts文件。保證了檢查過程的高效。
3. 當(dāng)你運行tsc build的時候,它也會進(jìn)行增量的構(gòu)建,只有當(dāng)引用文件發(fā)生修改過期的時候,才會重新構(gòu)建。
4.3.2 Lint遷移

1. 首先在你eslintrc.js文件中引入TS的parser與plugin。
2. Extends里面,建議就使用typescirpt-eslint這個包推薦的幾種配置。
3. 接下來把你團(tuán)隊原來的eslint規(guī)則包引入進(jìn)來,基本上你會發(fā)現(xiàn)原來所有eslint規(guī)則都是可以正常工作的。你也可以繼續(xù)使用rules屬性來覆蓋繼承的規(guī)則。
4.3.3 依賴遷移

1.對于那些本身已經(jīng)用TS來寫的依賴,你不需要做任何改變。正常import進(jìn)來就可以了。但是如果庫本身沒有自帶類型,那你就需要使用denitelyTyped這個庫,來把類型當(dāng)作dev依賴裝上就可以了。
2.然而如果DT里面也找不到類型定義。那你需要做的就是,在d.ts里面declare一下這個module,可以自己給它添加類型定義,最終發(fā)布到DT上。
3.更棘手的情況是類型找到了,但是有錯。導(dǎo)致明明我傳出正確的參數(shù),還是會看到惱人紅線,這里有兩種做法:1. 依賴類型聲明本身的寫法,你可以在import 類型后,通過extends或者merge的能力對源類型進(jìn)行擴(kuò)展。2. 修改類型錯誤,給DT提PR。
4.3.4 代碼遷移:混合模式

TS的遷移有兩種方式,一種是混合模式,也就是說,把a(bǔ)llowJs開關(guān)打開,然后一個個的把.js改為.ts,再修復(fù)類型。
4.3.5 代碼遷移:激進(jìn)模式

一次性的把所有js后綴全部改成ts。遇到比較難寫的類型,或者文件過大的時候。你可以分別使用@ts-ignore或者@ts-nocheck(TS3.7)來忽略掉下一行的類型檢查,或者整個文件的類型檢查。
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Part 5 總結(jié)
TypeScript之所以取得成功,有一個很重要的原因就是他的定位明確:讓JavaScript變得更好,而非取代。
很多沒有真正使用過TS的人,對TS的印象往往還停留在“靜態(tài)類型的JS”。而忽略了“提高生產(chǎn)力”才是TS目前的核心設(shè)計目標(biāo)。
56%的npm開發(fā)者都在使用TS,驚人的數(shù)字背后是確鑿的事實。
所以你還在等什么呢?
摘自:程序員黑叔