這是一個由 simviso 團隊對 JSConf.Hawaii 中關於大規模應用Typescript相關話題進行翻譯的文檔,內容並不是直譯,其中有一些是譯者自身的思考。分享者是Brie Bunge,Airbnb高級前端工程師。javascript
視頻地址:大規模應用TypeScript「2019 JSConf -Brie Bunge」前端
視頻翻譯文字版權歸 simviso 全部,微信公衆號:Simviso,未經受權嚴禁轉載java
本次參與翻譯人員react
你們好,個人名字是 Bree,我在 Airbnb 工做。git
在大公司中進行大的改革很難。這須要去說服不少人,同時又須要涉及大量的代碼遷移。我想要與你們分享咱們是如何將 TypeScript 應用到 Airbnb這個公司的平常開發中的。我感謝大家能在這裏,我知道大家徹底能夠披着時髦的毛巾在海邊娛樂。程序員
我設想這裏的每一個人都會有這樣一些問題, 你要爲你的公司進行重大的變革, 同時這可能會被做爲一個案例進行研究, 你如今是否在公司內部積極的推進將項目開發遷移到 TypeScript,爲此我將提供一些技術和工具上的幫助。github
或許,你已經聽過一些 TypeScript 的內容,而且想了解更多。typescript
首先,咱們會介紹 TypeScript 是什麼?規模化又意味着什麼? 對於將Typescript規模化的過程又有什麼建議? 基於這些問題和疑問,我會給出相應的解答, 咱們該經過什麼樣的遷移策略將 JavaScript 逐步遷移到 TypeScript。編程
請你們快速舉手示意一下以方便我知道大概有多少人以前使用過 TypeScript, cool,有這麼多人。 還有一部分人沒有舉手, 那麼,讓咱們快速介紹一下, 這樣每一個人都在同一塊兒跑線上了。後端
假如咱們有這麼一個 greeter 方法, 它接收一個name
參數,而後返回 "hello" + name。 So,若是咱們傳入的是"JSConf"
,它會和睦的說"hello JSConf"
。
可是在這種狀況下,若是咱們傳遞的參數類型不是字符串,而是一個字符串數組,那麼 TypeScript, 就會給咱們一個錯誤。即這是一個字符串數組,函數接收的參數類型是 string,不支持該分配。
咱們不須要再經過點擊刷新頁面這一流程來從咱們的控制檯中查看錯誤並肯定該錯誤所發生的位置。 能夠看到,在咱們輸入後,當即就從編輯器中獲得了這個錯誤。
person
對象。同時,你能夠定義更復雜的構造類型。 Typescript一般帶有一個編譯器, 當出現問題時就能夠立馬告訴你。 它還有一個能夠與編輯器掛鉤的語言服務器,能夠幫咱們進行自動編譯,提供重構相關提示等等
神奇吧!我不必來回瀏覽文檔頁面,我在編輯器中就能夠獲得這些全部。 經過在咱們的代碼中使用類型,咱們能夠作更多的事情。
咱們只是稍微接觸了下TypeScript的類型限制,可是能夠經過這個來幫你捕獲這種類型的錯誤,以及支持它的工具。
關於TypeScript的類型檢查內容就到此,那關於規模化應用這一部分呢?
若是你一時疏忽,輸入了一個錯誤的變量,那你將會獲得這樣的一個錯誤提示,so,在 TypeScript 中真的會發生這樣的事。 因此,讓咱們來修復下。
但當團隊規模達到數百位工程師,同時代碼量也愈來愈多,那麼交流方式就要發生改變。 咱們須要進行一些改變,即當咱們想要在咱們的主倉庫中使用TypeScript的時候(這裏指Powers | airbnb.com的主倉庫), 同時讓TypeScript成爲前端主要開發語言。 這個改變影響的人越多,那麼必須遷移的代碼也就越多,那咱們用數字來講明規模化意味着什麼。
這真的有不少代碼,我甚至能看到一些Backbone
的代碼。能夠想一下JavaScript走過了多少年,它在Airbnb這裏也走過了十多年。因此咱們有大量的開發人員在維護這些代碼,
目前公司有超過1300名開發人員,其中有200個是前端, 這些前端工程師大多數都參與了主倉庫的貢獻。
這些數字給咱們展示了當時咱們提議要使用TypeScript時所面臨的大環境。 那麼在這種規模下,咱們當時是一個什麼樣子呢?
你們會權衡這些提議的利弊, 咱們會站在團隊的角度去決定向前邁出這步是否有意義。 這確保了咱們能夠做爲一個集思廣益的團隊,對所作的事情作出深思熟慮的決定,這樣能夠避免在沒有正當技術理由的狀況下就「上車」。
從2016年起,Airbnb 已經在一些小規模團隊中探索使用 TypeScript。在2017年的前端調查中,靜態類型系統呼聲最高。 基於這個信號,Joe(第二排那個Joe)和我起草了一個關於TypeScript的提案,並將它交給前端工做組。 這項提案詳細說明了爲何在Airbnb使用TypeScript是有意義的。
讓我來說講主要的緣由。 airbnb的使命是要創建一個讓每個人都感覺到世界到處都是家(airbnb是一家旅遊住宿的公司), 用戶對咱們的產品提出的每個建議都能會讓咱們向着這個目標更進一步, 對於你正在開發的產品也是如此。
使用TypeScript,工程師能夠更安全快速的遷移代碼。 在Airbnb咱們引入了GraphQL 和Apollo,它可使咱們經過自定義的GraphQL模板來生成TypeScript類型
這意味着咱們能夠獲得端到端之間的類型安全, 由於前端和後端所使用的數據類型共享了同一個事實上的定義源, 後端工程師可以在不影響客戶端的狀況下對API進行修改,而前端工程師則能夠確信哪些數據將從服務器返回。
類型不匹配一直是咱們的主要bug所在。 因此,這種端到端的類型安全性是一個主要的賣點。
彷佛須要先將包轉換爲 TypeScript。 這看起來像是須要首先將這個包轉換爲TypeScript 但這裏有個問題,由於維護人員不容許咱們對它作TS轉換操做,可能他們也不情願這麼作。 由於在咱們提案的早期,咱們並不肯定是否要一直按照這個提案走下去。
可是從另外一個層面來說,咱們使用TypeScript是爲了可讓開發人員能夠有更好的體驗。 咱們須要TypeScript提供的類型安全性, 那麼咱們該如何解決看似雞和蛋的問題呢?
TypeScript有一個叫作聲明文件的功能, 即一個以.d.ts爲擴展名的文件,經過它咱們能夠爲JavaScript文件定義類型。
.d.ts
文件。 方法裏沒有實現細節, 它只描述了類型。 TypeScript將它們組合到一塊兒,這樣,在編譯是使用這個聲明文件,在運行時使用這個原生的JS文件。
因此,讓咱們回到最初的場景,看看聲明文件是如何提供幫助的。 那麼咱們回到咱們剛纔提的問題(要不要一開始就轉換),看看聲明文件是如何提供幫助的。 固然,若是那個項目已轉換爲 TypeScript,咱們就沒有必要再生成一個.d.ts
文件來做爲TypeScript構建時的一部分(由於在使用TS編程的時候,要經過它對生成的JS進行調用)。
但咱們認爲這不止一種選擇。 相反,咱們能夠將聲明文件放在咱們的 TypeScript 項目中。 另外一個選擇則是咱們能夠建立一個單獨的NPM包,並將全部聲明文件放入其中 。 這很棒,由於咱們如今能夠跨多個倉庫共享這些聲明文件。
@types/react
包中針對React的5000個經常使用包作了類型聲明, @types/react與其餘5000個其餘包都在
DefinitelyTyped
這個倉庫中,它由社區在維護
在咱們的主倉庫中,絕大多數的公共依賴都已經由DefinitelyTyped 作到了類型聲明, 有活躍的社區氛圍是TypeScript 的一個主要賣點。咱們也回饋了一點力量,我相信在這個房間裏也有人作出了貢獻,謝謝。 這些公共的NPM包的類型聲明已經有DefinitelyTyped
在作了,但那些內部的包該怎麼辦?
@airbnb-types/*
),這樣,你只須要安裝
@airbnb-types
便可 倉庫的設置相似於類型的明確性。 這個倉庫的設置與DefinitelyTyped相似 因此咱們能夠在裏面添加併發布這些內部類型。 咱們開源了一個starter 工具包,若是你又興趣的話,能夠來參與下。 它裏面沒有類型定義,它只是在教你如何進行一些配置以便於進行測試或者發佈本身的類型定義。
那麼 TypeScript 究竟能幫忙避免多少 bugs 呢? 近期,一個叫作「該不應作類型定義」的研究代表,在選擇了TypeScript 的 github 倉庫中,有 15% 的 bugs 獲得了避免。 在咱們內部,有一個記錄生產環境事故的流程。
這個流程的本意並非爲了責怪誰,而是要從錯誤中進行學習,這樣咱們以後就不會再犯相似的錯誤。 因此我坐下來讀了六個月的總結報告。 閱讀這些總結報告頗有意思, 我最喜歡的就是未捕獲的異常以及危險的參數計算。 好吧,也許這些錯誤的名字並無那麼使人激動。 不管如何,我將這些錯誤歸類爲與 JavaScript 相關或無關,以此肯定哪些錯誤能夠經過使用Typescript 來避免
讓咱們一塊兒看個例子,使用TypeScript會帶來哪些幫助 咱們對所分享的這個 Input 組件進行修改,經過一些設置來還原bug。 用戶沒法提交表單是由於它再也不能經過驗證。
onBlur
prop。 這就致使在好幾個不一樣倉庫中都出現了這同一個問題 這裏 Input 組件做爲Redux Form的一部分進行使用,指望獲得一個事件或值,以便驗證正常工做。
38%!
咱們發現有38%的事故致使了生產階段的bug。 這些對咱們用戶產生實際影響的bug,可使用TypeScript來阻止。 這對咱們來講是個巨大的發現。 它有助於實現影響。 它有助於將這種(積極)效果轉換到現實中。 咱們複製了一些BUG事件,並向你們展現了TypeScript所給出的Error提示,而後對bug進行修復(也就是咱們看到的bug提示燈泡滅掉了)
的確,咱們也能夠經過寫測試代碼來捕捉這些,可是經過靜態類型檢查能夠額外增長一層保護層。 所以,若是你所在公司有相似的歷史,那麼你可能就有必要和懂Typescript小夥伴一塊兒來看一下這些問題在大家的代碼裏所佔的比例。
咱們在主倉庫啓用超過了500條eslint規則,也使用typescript eslint解析器,咱們很高興地發現它們中的大多數均可以工做。 若是咱們在未來要棄用Typescript的話,咱們能夠剝離類型,並最終獲得大體相同的JavaScript。
因此咱們逐一記錄、思考、跟進,而且針對提出的問題和擔心找到解決辦法。 與批評者合做並聽取他們的擔心對咱們來講很是重要。 最後這些批評者中的大部分轉而會支持咱們, 咱們的提案也從他們的反饋中變得更爲健壯。
咱們已經解決了早期的矛盾,並改進了工具和文檔,因此以後團隊成員會更容易入門。
咱們一直與 typescript 團隊保持着持續聯繫, 並幫忙解決一些問題,好比,更好的默認屬性優先級處理。
在這個階段,咱們本身內部的 typescript 社區也獲得了發展。 可是大部分 Airbnb 的員工還不知道 typescript, 這也意味着更多的人能夠去幫助和回答他們的問題。 接下來咱們將會進入測試狀態,團隊能夠選擇使用它。 爲了幫助團隊,咱們建立了內部文檔和風格指南,並舉辦了一些學習課程。
咱們創建了一個聊天組,一個內部的類Stack Overflow,谷歌Email主題,github組,來供組內成員交流。 咱們想確保人們能獲得他們須要的幫助, 最後一步是將 typescript 徹底普及化。 此時就意味着它是穩定狀態,每一個人都應該開始使用它, 咱們目前正在努力地去接近這個目標。 剩下的步驟就是鞏固風格指南、文檔、增強內部培訓和遷移更多代碼。 到目前爲止,咱們大約有50%的團隊使用 typescript,在主倉庫中,有10%的文件已經被轉換成 typescript 經過這種漸進的方法,使團隊遷移至 typescript 的過程更加順暢。 若是從第一天開始就要求每一個人應該使用TypeScript, 那麼接下來的每一個人都會遇到一樣的問題。 相反,咱們先在小範圍內使用 typescript ,而後總結一些經驗技巧,當咱們準備把它大規模推廣時,這些經驗技巧也會用得上。
咱們已經探索出了幾種將代碼遷移至 typescript 的方式。
在關於遷移的話題上,我想花些時間和你們分享一些咱們認爲有用的技巧。
$TSFixMe
, 咱們經過TypeScript的any類型添加了一個全局類型別名,這意味着它能夠爲任何類型。 咱們將它稱之爲$TSFixedMe,代表在代碼向TypeScript遷移完成後,再來將類型修正 平時最佳實踐是避免使用
any
,由於它會形成類型安全丟失,但它在遷移過程當中會頗有幫助。
@ts-ignore
註解能夠作到忽略下一行錯誤。 正確地輸入一個文件可能涉及一些深層依賴鏈解析(相似於複雜對象)。 咱們能夠嘗試經過首先轉換子文件來避免這種狀況,但有時這是不可避免的。 所以,$TSFixedMe和@ts-ignore註解可以幫助拆分這些內容,同時則會增長這些檢查工做。 這些都是暫時的,咱們計劃添加類型覆蓋工具,並在後面咱們改進類型時提供幫助
爲了不重複兩次類型聲明,那就須要與這些類型保持同步。 咱們建立了一個Props
類型,經過它將給定的propTypes
和defaultProps
來派生出一個TypeScript類型。
propTypes
和
defaultProps
組合並獲得這個最終類型。 若是你好奇它是如何工做的,你能夠查看我在gist上分享的
代碼片斷。
爲了經過編譯,有些文件須要進行一些TS Fixed, ts就能夠推斷出剩餘部分。
在這個網頁下,它有一個能夠經過源代碼輸出對應的AST樹的功能,以及在你對代碼的改變同時反映到AST樹上。 我也在DefinitelyTyped 這個庫提交了關於Jscodeshift的pr,這樣的話能夠來下降你們在使用TypeScript與Codemod的交互門檻,
在將JavaScript代碼遷移到typescript時,有這幾種模式。
隨着時間的推移,你仍然須要慢慢找到類型,但它爲你提供了一個工做前提。 咱們將此工具應用於咱們的內部分享的React組件庫,如今在咱們的網站上已經頻繁地使用。 咱們有內部的類型定義庫(DefinitelyTyped),可是由於react分享組件庫的快速發展,因此作到與時俱進地更新太難了, 因此,咱們想直接從源碼類型出發。因此這是咱們遷移TS的第一個目標。
在大型組織中實施變革多是一項挑戰,但強有力的事實依據和相關問題和擔心的解決,可使咱們信服。 採用逐步變化的方式有助於減小摩擦並證實其價值。 一條明確的遷移路線能幫助團隊更好的轉向新的模式,同時好的工具也能促進這個過渡的過程, 我之因此開始這個工做,是由於以前有個產品組對個人工具感到失望。 當我得知公司內部其餘人也有這種改變的想法的時候,我便與他們合做並將之進行下去。
感謝你們的傾聽,同時感謝AirBnb爲這個項目做出貢獻的每個人,尤爲是臺下的Joe和Mohsen。還有對其餘一些優秀的Airbnb工程師表示感謝。 我手上也有些TypeScript主題的小便籤和一些鑰匙鏈,先到先得,只限前30人哦!
感謝你們的傾聽。