Flow靜態型別檢查及在Vue專案中的使用

美團點評點餐發表於2019-03-04

前言

結合由Facebook出品的靜態型別檢查工具Flow,和最近將Flow引入到一個Vue.js專案中的實踐經驗,本文想聊聊Flow型別檢查工具和它在Vue專案中實際使用的效果。

目錄

  • 為什麼需要引入型別檢查?
  • Flow是什麼?
  • Flow的作用
  • Flow在Vue專案中的使用
  • Flow的配置過程
  • 在Vue元件中使用Flow的幾個方法
  • 型別檢查工具對團隊有什麼好處?
  • 總結

為什麼需要引入型別檢查?

JS作為一個弱型別語言,一個著名的黑點是它很容易就寫出非常隱蔽的隱患程式碼,在編譯期甚至執行時看上去都不會報錯,但是可能會發生各種各樣奇怪的和難以解決的bug。
型別檢查是當前動態型別語言的發展趨勢,根據stateofjs的調查結果,JS的強型別超集TypeScript已經有了相當的知名度,吸引了大量開發者的學習興趣,並且大部分開發者計劃繼續瞭解或者使用。


所謂型別檢查,就是在編譯期儘早發現(由型別錯誤引起的)bug,又不影響程式碼執行(不需要執行時動態檢查型別),使編寫js具有和編寫Java等強型別語言相近的體驗。它可以:

  1. 使得大型專案可維護
  2. 增加程式碼的可讀性
  3. 通常會有更好的IDE支援

Flow是什麼?

Flow是一個由Facebook出品的JavaScript靜態型別檢查工具,它與Typescript不同的是,它可以部分引入,不需要完全重構整個專案,所以對於一個已有一定規模的專案來說,遷移成本更小,也更加可行。除此之外,Flow可以提供實時增量的反饋,通過執行Flow server不需要在每次更改專案的時候完全從頭執行型別檢查,提高執行效率。
Flow和Typescript都是給Javascript增加型別檢查的優秀解決方案,兩者的簡單對比如下:

工具 Flow Typescript
公司 Facebook 微軟
star 12k+ 23k+
文件支援程度 中等 更多
第三方庫支援工具 Flow-typed tsd
IDE支援 Webstorm自帶外掛支援 Webstorm支援,Visual Studio原生支援
其他 自由度更高,老專案的遷移成本低 工程化強,社群活躍度和官方支援力度更高,適合新專案

兩者在程式碼語法上有大量相似的地方,除了對於一些資料型別的支援不一樣,具體請檢視Flow的文件。關於Flow和Typescript的比較,可以簡單總結為:對於新專案,可以考慮使用TypeScript或者Flow,對於已有一定規模的專案則建議使用Flow進行較小成本的逐步遷移來引入型別檢查。

Flow的作用

一個簡單的demo如下。


執行Flow命令,這個demo的執行結果如下圖所示:


對於需要使用 Flow 進行型別檢查的 js 檔案,在開頭加入 @Flow 註釋,即可引入Flow。通過demo可以看到,Flow可以幫助找出由於不合理的型別操作引起的錯誤,包括運算子操作,函式引數型別和返回值型別等。Flow也支援自定義型別宣告,泛型宣告等型別語言相關的操作,詳細的內容可以參考文件:Flow.org/en/docs/lan…

Flow在Vue專案中的使用

Flow在Vue專案中的具體使用價值有:

  • 使用Flow可以在不需要重構整個Vue專案(如UI元件遷移成本)、不需要引入大量的工具鏈(eslint+babel)、不需要第三方庫一定支援的情況下引入靜態型別檢查
  • Vue.js官方對TypeScript做了支援,但是專案所依賴的第三方庫不一定支援TypeScript,從全域性考慮TypeScript的遷移成本比較大
    在嘗試Flow+Vue.js的實踐過程中,主要的步驟包括:1,使用Flow-typed工具(github.com/Flowtype/Fl… packages的支援;2,在一個由Vue cli (webpack + babel + eslint) 生成的腳手架專案中配置 Flow(見後文);3,Vue 的單檔案元件結構如何支援 Flow,在業務專案的實踐中前後使用了三種方案,也會在後文分別介紹這幾種方法和其優缺點。

Flow的配置過程

  1. 假設目前有一個從vue-cli命令列生成的專案:vue init webpack-simple Flow-vue-demo。關於Babel,Eslint(可選)和Flow,需要安裝所需的 npm packages,參考列表如下:

Babel:

  • babel-plugin-syntax-Flow
  • babel-plugin-transform-class-properties
  • babel-plugin-transform-Flow-strip-types

Eslint: (可選)

  • eslint
  • babel-eslint
  • eslint-plugin-html
  • eslint-plugin-Flowtype-errors
  • eslint-plugin-vue
  • eslint-config-vue

Flow:

  • Flow-bin
  1. Webstorm自帶了Flow的支援,需要開啟,結合eslint配置Flow相關的rules,在編輯時通過eslint即可自動報錯。
  2. 安裝Flow,執行Flow init && Flow check。配置.vue檔案為Flow的檢查範圍。
  3. 使用 Flow-typed 處理第三方的 npm packages 的型別宣告。
  4. 必要的話增加自定義的型別宣告檔案,如自定義的物件等,具體可以參考Flow文件。

在Vue元件中使用Flow的幾個方法

在前面的demo中已經展示了純JS檔案裡面怎麼用Flow,那麼在一個vue元件檔案中應該如何配置呢?有下面幾種方法。
方法一:直接在script標籤中,像純js檔案處理一樣新增Flow註釋,發現可以正常編譯執行,但是執行Flow check是無效的。
方法二:註釋掉template, style和script標籤,由於Vue的編譯器即使註釋了也會識別其中的<template>, <style> 和 <script> 標籤,而Flow檢查會忽略註釋,因此對於Flow來說可以當做一個javascript檔案進行處理。demo如下圖所示。

對於這樣處理的vue檔案,Flow命令能夠報出關於一般的函式宣告的型別檢查錯誤,但是對於繫結到Vue例項(this)上的方法是無效的。因此Flow型別檢查不是100%覆蓋。這種方法的主要問題在於程式碼和註釋混用不便於閱讀,目前Flow社群有一個open issue就是關於這個問題的,即不能自動檢測中檔案中的script標籤,請見:github.com/facebook/Fl…

方法三:Vue檔案引用外部的js檔案,將js部分單獨抽離出來進行型別檢查。該方法的優點在於可以用到Flow的所有功能,但是沒有了vue單檔案元件的結構,專案結構略顯臃腫。(每個元件都會有至少兩個檔案)。如下圖:

三種解決方法的優缺點對比如下表所示:

方法 Pros Cons
標籤中直接新增Flow 程式碼新增量最小 Flow 型別檢查無效. 不予考慮
註釋template中的標籤 1. 可以通過Flow check檢查出部分的型別錯誤 2. 最接近使用直覺. 目前是一個open issue 1. 對於和元件無關的函式以及import. 可以正常工作. 但是不是100%覆蓋 2. 看上去樣式比較糟糕
Vue檔案引用外部的js檔案 1. 通過eslint中通過使用Flow外掛. 配置Flow規則. 可以在編輯時實時提示 2. 沒有影響檔案結構 3. 單獨的js檔案可以幾乎完全使用Flow的所有功能 1. method仍然不能自動識別. 由於Vue中的一些函式一般沒有return value. 需要手動判斷型別防止bug 2. 一個元件的程式碼被分拆到多個檔案. 不如單檔案元件那麼直觀

型別檢查工具對團隊有什麼好處?

通過在一個Vue技術棧的實際業務專案中引入Flow,我們大致獲得了這些收益:

  1. 幾乎消滅了由函式資料型別引起的bug
  2. 無需額外的關於變數、引數、返回值型別的註釋,可以讓讀者瞭解必要的附加資訊
  3. 大量減少由於使用第三方庫不當引起的型別錯誤
  4. 可以在CI系統中整合
  5. 工具鏈配置成本比較低,只需要很少的工作量即可達到這些效果

關於型別檢查工具,讀者可能需要考慮的問題,回答如下表所示。

Question Answer
型別檢查可以讓我的程式碼bug free嗎? 不能保證bug free,只能檢查型別錯誤
可以提高我的生產力嗎? 需要多寫一些程式碼,但是相應地可以減少很多runtime debug的時間
將Flow引入我的專案,所需要的工作量大嗎? 不大,可以逐步引入
我的專案需要長期維護? 請使用Flow或者Typescript
我的專案非常簡單? 簡單專案不一定需要型別檢查,可能會有些多餘
我的專案需要重構? 請引入型別檢查
我的專案對於bug free的要求非常高? 請引入型別檢查,減少型別錯誤等難以發現的bug
我的專案開發人員流動很頻繁? 請引入型別檢查,增加專案可讀性
我的專案有大量的演算法計算? 請引入型別檢查,減少隱蔽的型別轉換錯誤等

總結

  1. Flow或者TypeScript都是靜態型別檢查的優秀解決方案,能夠給有型別檢查需求的一定規模的專案帶來實際收益。
  2. Flow+Vue目前看來有些使用上的不便,期待儘早解決open issue,能夠自動識別Vue元件檔案的標籤,從而使得Flow在vue專案中的使用更加流暢。

相關文章