為何大多數人和新的項目不用 TypeScript 而用 JS + 一堆輔助工具?

TypeScript 已經很完善了:.聲明文件、IDE 支持、強大的社區和更新速度,為何大多數人和新項目還執著於 JSLint、ESLint、Babel 全家桶、Flow 等一大堆零亂的工具和雜亂無比的配置文件,寫各種文章和 Blog 來傳播這堆工具的配置過程?


先表明立場(以免被無腦噴):我喜歡靜態類型檢查,也很認可 ts 的價值。

但是出於這幾點因素的影響,導致我在項目選型時並不是每次都能毫不猶豫的選擇 ts:

  1. ts 生態繁榮程度不如 Babel。很多流行庫都有相應的針對打包體積優化的 babel plugin,如 lodash/babel-plugin-lodash date-fns/babel-plugin-date-fns 等,拋棄 Babel 的話你就無法享受這些收益。當然這個問題你可以用 @太狼 的 ts-import-plugin 來解決,抑或是等 webpack next 的 pure-module 方案 webpack side-effects field 。但這只是其中一個問題,babel plugins 能做的遠不止這些。又或者你可以用 ts 寫然後 tsc --target es6,然後再用 babel compile 一遍,但又不一定所有的 babel plugin 都能很好的支持 ts compile 出來的代碼。再或者基於 babel 7 的 babel-plugin-transform-typescript 直接用 babel 編譯。但這一切你還是離不開 babel。
  2. babel(plugin) 對同一語法特性的編譯處理方式跟 ts 可能不一致,從而導致編譯後的 代碼在某些 edge case 里產生不同行為。

    拿 decorator 舉例,babel(指 babel-plugin-transform-decorators-legacy) 對 decorated class property 的處理方式是在構造函數中搭配 initializer 初始化 this,ts 的做法則是直接將 field 掛載在 prototype 上 decorate。這導致了在 ts 編譯的代碼中,如果你想通過 Object.keys(instance) 的方式遍歷被 decorated 的 class property 自然就行不通了。這種不一致帶來的問題是第三方庫的開發者還得考慮 compiler output 的兼容性: https://github.com/mobxjs/mobx/blob/master/src/utils/decorators.ts#L18。

    當然,decorator 這個例子可能有點特殊,而且不應該由 ts 來背鍋,畢竟這種不一致是其 spec 一直以來的不穩定導致的歷史問題(具體看這裡 Trotyl Yu:TypeScript中的裝飾器(Decorators)的本質是什麼(或者說它具體做了什麼工作)?),但是我們很難保證在其他語法特性的處理上,babel 跟 ts 能始終一致,而其帶來的兼容性問題卻是任何一個開發者都不想看到的。

  3. TS 官方只支持 stage 3 及以上的新特性。這個就不多說了。
  4. 開發成本考慮,團隊成員及項目特性兩個方面。老生常談的話題,這裡不多說。當年的「為什麼還用 es5 而不用 es6 」也會碰到這個問題。不過有一點不一樣的倒是,學習 es 新的語法特性的收益是顯而易見的,但是 ts 的投入回報並不一定會被所有人認可,畢竟 ts 不是 es。所以作為原教旨主義的我而言,如果哪天 es 中加入了靜態類型檢查特性機制,我可能就不會考慮 ts 了... 那麼為什麼目前為止我沒有選擇 babel + flow 的組合而是寫 ts 呢?當然是相較而言,ts 的生態比 flow 更繁榮啊...


我分幾個方面回答這個問題。

首先,肯定有越來越多的新項目採用了 TS 了的。題主在某種程度上是過於心急了。一個東西再好,普及也是需要時間的。比方說,在2015年可能有人會問『為何大多數人和新的項目不用 ES6』?但到了2017年就不會有人問了。那麼 TS 在什麼時候就不用問了?最保守的說,當可選靜態類型(接近)進入 ES 標準時,就不用問了,因為那時 TS 基本就等於 JS 了。(先別打我,看到最後再說。)

我們需要注意,TS 達到目前的成熟度也不算很久,以我粗淺的 TS 使用經驗,可以說,在 TS 1.x 的時代,其類型系統離覆蓋絕大部分 JS 用法還差得很遠,對於我這種非常討厭看到 any 和強制 cast 的人來說,經常惱火於 TS 的不足,常常要上 TS 的 repo 去查 issue 和提(tǔ)意(tǔ)見(cáo)。更不要說連 null check 還沒有的更早期。即使目前 TS 2.3,對某些 ES 2015 特性的支持也尚未完善(比如 spread/rest)。比較挑剔的人選擇再等待一陣也是很正常的。

此外,儘管 TS 現在已經很強大了,就類型系統來說,某些方面甚至已經反超了 Flow,但是遠遠談不上可以碾壓。比方說,TS 到目前為止仍然是 unsound 的,並且這是 by design 的。對於那些對類型系統的 sound 具有潔癖的人來說,他們還是可能選擇 Flow,甚至 Reason/BuckleScript,甚至 Kotlin,甚至 Idris……反正任何一種可以編譯到 JS 的靜態類型語言嘛。

題主提到的輔助工具,JSLint(DC 寫的那個)其實早沒有人用了。至於 ESLint,既然不用 TS,那當然還是要用的。這個沒有什麼可說的。關鍵的問題,大概是 Babel。題主認為 TS 可以取代 Babel,大概是因為 TS 已經完全支持 ES2017,並也已經可以編譯到 ES5、ES6、ES7 等多個 target。的確,從最主要的 use cases 上來說是可以做到跟 Babel 一樣的事情。但是 Babel 的意義早已不是僅僅從 ES6 編譯到 ES5。它的插件化架構,使其涵蓋了語法轉譯、代碼靜態分析、代碼質量檢查、代碼修改工具、代碼壓縮等更廣泛的領域。Babel 的超高可定製性,大量插件,涉及工具鏈上下游之廣,這都是 TS 目前還比不上的。因此就整體來說,Babel 在許多工程中仍然是不可取代的。

特別的,可能因為類型系統的複雜性所導致的成本,TS 對於 JS 新 proposal 的支持是比較保守的,一般都要到接近進入標準(stage &> 3)才會開始開發。而 Babel 則支持了大量的 stage 0 的特性。這使得 Babel 在整個 JS 標準進化中,具有非常重大的意義。我在很多地方都講過 Babel 在 JS 生態里所具有的至關重要的作用和地位。請參考我的演講:The World"s Best Programming Language 。

最後,怎樣算用 TS?我的應用還是用 JS 寫,但是我的編輯器、IDE 自動使用了我的依賴 packages 里的 d.ts 定義文件,提供了代碼提示、自動完成、部分的類型檢查……這樣算不算用 TS?實際上,許多比較簡單的業務項目里基本上就只是現成 API 的調用,或在現有框架下填空,幾乎沒有需要手動標註類型的場景,直接用 JS 反而更方便。

另一種情況,我是寫 TS,但是構建部署還是使用 Babel(即將發布的 Babel 7 支持擦除 TS 類型),這樣算不算用 TS?實際上,這種情況下,TS 和 Babel 共存於同一個項目,各自發揮作用。

Babel 的這一重要改進,會極大的促進 TS 被引入更多的項目。回到我最初說的『什麼時候不用問了』,最 aggressive 的說,當 Babel 7 被普遍採納之後,就不用問了,因為絕大部分(尚未使用TS的)工程方案都使用 Babel,屆時,即使一開始一個項目沒有用 TS,你之後只要略微修改下 Babel 配置,就隨時可以在任何一部分源代碼里開始使用 TS 特性。

以上。


我們最近的項目都是 TS 了(前端和Node端),早期也是很糾結第三方庫沒有 .d.ts 文件搞得編譯時很是傷心,然而在 TS 2.2 還是 2.3 版本發布後,這一切已經不是問題,么有 d.ts 文件的有時間自己寫一個,沒時間就直接 any 使用吧。因為我們的項目業務邏輯都比較複雜,在使用 TS 作為開發語言至今也有大概 1年半的時間了,現在前端同學再去寫純 js 的時候就很難接受沒有強類型支持和異常強大的自動提示了。

我們使用 ts 開發了 h5 版本的 reporting designer 和 sass 版的企業應用。感謝 typescript 帶給我們更好的代碼質量和開發效率!


對於很多項目來說,強類型並非必需,只要完成業務功能按時交付就可以了。

越是基礎、上規模的項目,對 TS 的內在需求越高。反之,快糙猛上線才是硬道理。


TS類型系統還不是很完備,部分情況無法描述——只能用一個很寬泛的類型甚至any來做標註,強迫症表示不爽。。。(因為更為致命的是,這種寬泛的類型會被自動推導所擴散——除非不用自動推導,然後代碼里就一堆類型轉換。。。)

例子的話,就比如說Rambda,就沒有一套完美的方案。。。

而這種特點使得在自己做一些庫的時候,也很可能被TypeScript牽著鼻子走,具體實現沒寫多少,各種泛型介面倒是寫了一堆,還要思考各種範疇論的思想,去完善類型標註(然後TS對於高端點的泛型的支持又是一坨屎,例如Type inference not working for this particular use of Generics? · Issue #8952 · Microsoft/TypeScript)最後還是弄了一個any。。。


這個問題的許多回答都對 TS 有誤解。

可以說這也是不用 TS 的一個原因。

-----

簡單舉幾個例子

TS類型系統還不是很完備,部分情況無法描述

難道非要用 GHCJS 或者 Idris?TypeScript 支持JS常用表達的類型系統是其他語言比不上的。Lookup Type / Mapped Type / String Literal Type 都不是一般語言里有的。 真要用 Category Theory寫前端?Elm 的類型系統估計都不夠用。

然後TS對於高端點的泛型的支持又是一坨屎, 例如Type inference not working for this particular use of Generics? · Issue #8952 · Microsoft/TypeScript

確實是一坨屎,不過這個例子也是一坨屎。類型推導一般不會從 bound 反推回 variable,比如 Scala也不行(當然你也可以說 Scala 是屎)。原因就是這些語言(指通過 AST 語法制導進行類型檢查的語言)的 Type Bound 是被當成作為 Inference 之後的 Check 寫的。就算不是語法制導的檢查器,比如 Flow,也不會通過這個測試案例。

此外這段代碼本身也不是正確用法

function unwrap&&>(x: T): I

這個函數簽名里 T 根本沒有返回,是一個廢變數。不知道這麼寫的用意是為何。用這樣的案例來說明 TS 的類型系統不好,實在沒有說服力。

正確黑的姿勢: Constraints cannot be proven in mapped types combination · Issue #13039 · Microsoft/TypeScript

不過 flow 的優勢在於並不強制要求完整的類型覆蓋

any

You have any, any way. 至於說 Flow 的類型覆蓋率,真正用過的人就知道是個笑話。

和某些工具結合使用時有點麻煩。比如vue。

ts-loader 可以編譯 vue 文件,vue 有天生的 d.ts,還有官方的 class component。如果追求 type coverage 可以用第三方包裝更激進的庫。用 TS + Vue 的麻煩程度,基本和 用 Babel 差不多的。都是配置 loader + 引入庫依賴。

但是,強類型寫起來是很繁瑣的,特別是處理一些複雜的對象結構 ...... 從json struct到orm struct還有一次轉換,一個介面的代碼可能有一半都是在處理數據之間的綁定、轉換,而最後我可能只是想簡單的寫到資料庫而已。。。想想用js這種弱類型來處理會多麼幸福。

想想js 這種弱類型來改資料庫欄位會多麼酸爽。


TypeScript 很好呀,2年前我就在用。當時 ng2 決定擁抱 ts 的時候,我還著實激動了一下。

ts 有著類型於 java 的語法,配合上 ng 依賴注入簡直爽歪歪有木有。有了類型,代碼提示更加完善,實在不清楚 api,點進去看定義文件,很方便有木有?

然而為什麼推廣不開那?大概因為前端圈有後端基礎的人實在是少數(有一點後端基礎的人,都會覺得 ts 更親切),大多數轉行而來的人,都想待在自己的舒適區里不出來吧。

誠然,ts 也有它的問題,比如編譯到 js 會類型抹去,運行期無法獲得類型的問題,造成很多類型上的細節實現運行時有可能出大大小小的問題。但是不可否認,大型工程中,多一個類型檢查,還是多一份安全感


原因很多吧:

1. 我覺得前端沒有新人老人的說法,只有專業與業餘的說法。業餘的人寫ts的難度肯定比js大。

2. 項目代碼已經很多了,難以改造(比如我司現在的可視化項目)

3. 成本問題。ts的開發成本要高於js

4. 負責人眼界問題:看不到維護成本ts要小很多。

5. 小公司小項目沒必要用ts,可能下個月這個公司就不在了,快速迭代才是主旋律。

6. 在過去兩年能夠整合ts進項目的前端人員較少,現在好得多了。

建議:如果你的服務端是node,但你又不想寫test case(畢竟前端寫的伺服器不是那麼規範),可以考慮引入ts,可以有效減少部署的次數~


用 ng 的人就不用考慮這個問題了,默認就用 TypeScript。

ng 多貼心,幫助你學習新語言。

用 React 和 Vue 的人不用 TS,可能是因為沒有看到好的例子,或者例子太多眾說紛紜,不知道怎麼用才是最佳實踐吧。沒想好怎麼用,就先不用咯。

而 ng 把例子都寫在文檔里了,教你用。

你們不知道 ng 有多努力!!!


手機碼字,若有錯誤請指正。目前我司各產品線是自由選擇 ts 或者 babel + flow 。在大部分語法使用上,flow 和 ts 並沒啥區別,不過 ts 特性完善確實比 flow 要好,還有 vscode 這樣的殺器;flow 還不支持一些 es6 特性呢吧。

不過 flow 的優勢在於並不強制要求完整的類型覆蓋,對於很多老項目的改造會比 ts 好很多。而且筆者個人感覺,你想要類型覆蓋率 80% 還算容易,要達到 100% 務必要為類型檢測添加很多的空檢測,類型檢測這些額外的代碼。這讓我彷彿在寫 java ,無數的類型轉換,這也失去了動態語言得一個優勢吧。

在寫庫的時候,往往會需要代碼儘可能的少。這時候筆者會優先選擇 flow ,然後解決一些比較重要的錯誤。另一個筆者是用 rollup 打包庫類型的項目,想要保留 es6 的模塊,但是轉化其他語法(類成員,裝飾器)這些,好像 ts 就有點無力。

還有一個考量是 Babel 的插件支持,我司目前也有一些自定義插件。

最後,主觀來說,我希望使用 js 的擴展而不是另一門語言。


使別人接受是一個他不感興趣的東西,這是一件很艱難的事情。

至今為止還有許多人認為Typescript只適合大型項目,甚至於某著名框架的官網上還寫著這樣的論調,這也不是個人觀點能夠左右的事情。

總之,提問的語氣錯了。

關於Typescript……

ts的社區的確不錯,現在聲明文件現在覆蓋面已經很廣了,不過偶爾也會遇到沒有聲明文件的庫,用起來會稍微有些難受。

關於Lint……我覺得Typescript和lint並不是衝突的,事實上也還有tslint呢……

babel……馬上就能編譯Typescript了。

可能讓人覺得不適應的地方……

代碼比起js繁瑣一些,利用到複雜一些的泛型之類的特性時稍微有些燒腦。

Typescript在模塊化那一部分的組織因為各種各樣的歷史原因所以好像有點混亂。

和某些工具結合使用時有點麻煩。比如vue。


我用TS幾年了,越用越舒服。

TS是獨立的語言,可以在TS語言層級做很多事情。

目前的生態發展看,喜歡就用,不會影響什麼。


項目就點點模塊沒必要,ES2015 沒毛病,不過我覺得你寫熟了 ts 也不會在意用不用 ts ~


因為 Babel 可以給我們非常精細的控制,雖然大部分場景可能不需要用到那麼細。這其中典型一點的就是 babel-preset-env, 你可以控制讓 Babel shim 你的 JS 到具體哪一個瀏覽器版本或者 Node.JS 版本。

甚至還有更精細的例子。前一段我需要編寫 Adobe 的 ExtendScript,一個 ES3 規範的 JS 語言。為了不放棄"現代生活",我用 Babel/Browserify 把它 Shim 到了 ES5 的層面。然後用 CoffeeScript 1.0 來寫(盡量現代化)。這裡要說的事,這種需求就只能通過精選 Babel Plugins 來完成,甚至為了避開 ExtendScript 中的 Bug,需要修改某些 Babel Plugin 的源代碼解決。

一大堆輔助工具雖然很幸苦,但是還是能帶來"選擇權"作為回報。


因為ES是標準,TS是方言


任何脫離場景談技術都是耍流氓...

你用 TS 去維護很多公司的老項目試試?特別是那些需要考慮瀏覽器兼容性的 To C 項目...

換個角度來看,你讓老員工去維護你的 TS 項目試試?

如果需要用新技術,那就必須所有可能參與開發的同事都贊同的情況下才可以,而且需要承擔新技術所帶來的不可預知的風險。

在公司里協同開發肯定是重於個人開發的,每個大公司或多或少會有一些爛尾的項目存在,那些項目可能在那時就是一些新潮的技術實現...

新項目是可以嘗試用新技術,但你得明確一點就是你的項目是否有其他同事共同參與的,需不需要協同開發?一旦用了新技術,那麼參與的同事就必須會 TS,這也是一種成本。並且你還得保證之後的同事在接手你的項目之後能夠較輕鬆的去維護該項目。

各種技術的存在都有其意義,不同場景下的選擇也應該是不同的。妄圖以一種技術替代其他相似的技術那才是不可思議的事...


TypeScript 也有 Tslint啊……

目前 TS+React+Redux全家桶 路過……

你說我一個寫PHP的 怎麼就去寫 TS了呢……

(逃……


有兩個重要原因:

  1. TS的發展時日尚短,大家需要時間學習和慢慢融合。 如果手頭的項目已經再用ES5,ES6寫了,也不太可能覺得TS好就全部推到重寫
  2. 網上目前大多的Boilerplate和教程依然是基於JS的(如說大多的React項目)。所以為了方便上手學習,或者基於Boilerplate寫代碼,很多情況大家下就默認用JS了。與之相對應的是:Angular2由於官方支持的第一語言是TS,很少會有人用JS和Dart去搞Angular2項目


大多數人寧願花費更多的功夫去編碼,重構,debug,也不願意去學習一門「新」的編程語言,哪怕ts的學習成本幾乎為0,但是學習ts的成本是額外成本,正所謂「我不用ts不也寫的好好的嗎」

為什麼這麼說?因為這個問題下有某些答案錯誤百出,我估計這些答主對ts的了解應該來自於百度知道和某些「社區」吧

沒用過,不了解,咱就不回答成么


若無必要,勿增實體。大部分人找到舒適區就不想挪窩了,所以如果新技術沒有解決痛點還是不要折騰,按最熟悉的來。至於某位公司寫著前東家的前端培訓師陰陽怪氣的話,無視吧,是Angular選擇了TypeScript而不是TypeScript選擇了Angular。


推薦閱讀:

IDE中,選中一個變數,文檔中其它地方的該變數也會高亮,這種功能叫什麼?如何實現的?
2017你覺得未來五年最具前景的一門編程語言是什麼?
是否有函數式編程的優秀實例?

TAG:前端開發 | JavaScript | TypeScript |