Flow-vue源碼中的應用

認識 Flow

Flow 是 facebook 出品的 JavaScript 靜態類型檢查工具。Vue.js 的源碼利用了 Flow 作了靜態類型檢查,因此瞭解 Flow 有助於咱們閱讀源碼。html

#爲何用 Flow

JavaScript 是動態類型語言,它的靈活性有目共睹,可是過於靈活的反作用是很容易就寫出很是隱蔽的隱患代碼,在編譯期甚至看上去都不會報錯,但在運行階段就可能出現各類奇怪的 bug。vue

類型檢查是當前動態類型語言的發展趨勢,所謂類型檢查,就是在編譯期儘早發現(由類型錯誤引發的)bug,又不影響代碼運行(不須要運行時動態檢查類型),使編寫 JavaScript 具備和編寫 Java 等強類型語言相近的體驗。node

項目越複雜就越須要經過工具的手段來保證項目的維護性和加強代碼的可讀性。 Vue.js 在作 2.0 重構的時候,在 ES2015 的基礎上,除了 ESLint 保證代碼風格以外,也引入了 Flow 作靜態類型檢查。之因此選擇 Flow,主要是由於 Babel 和 ESLint 都有對應的 Flow 插件以支持語法,能夠徹底沿用現有的構建配置,很是小成本的改動就能夠擁有靜態類型檢查的能力。git

#Flow 的工做方式

一般類型檢查分紅 2 種方式:github

  • 類型推斷:經過變量的使用上下文來推斷出變量類型,而後根據這些推斷來檢查類型。api

  • 類型註釋:事先註釋好咱們期待的類型,Flow 會基於這些註釋來判斷。數組

#類型推斷

它不須要任何代碼修改便可進行類型檢查,最小化開發者的工做量。它不會強制你改變開發習慣,由於它會自動推斷出變量的類型。這就是所謂的類型推斷,Flow 最重要的特性之一。數據結構

經過一個簡單例子說明一下:函數

/*@flow*/`` function split(str) { return str.split(' ') } split(11) 

Flow 檢查上述代碼後會報錯,由於函數 split 期待的參數是字符串,而咱們輸入了數字。工具

#類型註釋

如上所述,類型推斷是 Flow 最有用的特性之一,不須要編寫類型註釋就能獲取有用的反饋。但在某些特定的場景下,添加類型註釋能夠提供更好更明確的檢查依據。

考慮以下代碼:

/*@flow*/ function add(x, y){ return x + y } add('Hello', 11) 

Flow 檢查上述代碼時檢查不出任何錯誤,由於從語法層面考慮, + 既能夠用在字符串上,也能夠用在數字上,咱們並無明確指出 add() 的參數必須爲數字。

在這種狀況下,咱們能夠藉助類型註釋來指明指望的類型。類型註釋是以冒號 : 開頭,能夠在函數參數,返回值,變量聲明中使用。

若是咱們在上段代碼中添加類型註釋,就會變成以下:

/*@flow*/ function add(x: number, y: number): number { return x + y } add('Hello', 11) 

如今 Flow 就能檢查出錯誤,由於函數參數的期待類型爲數字,而咱們提供了字符串。

上面的例子是針對函數的類型註釋。接下來咱們來看看 Flow 能支持的一些常見的類型註釋。

#數組

/*@flow*/ var arr: Array<number> = [1, 2, 3] arr.push('Hello') 

數組類型註釋的格式是 Array<T>T 表示數組中每項的數據類型。在上述代碼中,arr 是每項均爲數字的數組。若是咱們給這個數組添加了一個字符串,Flow 能檢查出錯誤。

#類和對象

/*@flow*/ class Bar { x: string; // x 是字符串 y: string | number; // y 能夠是字符串或者數字 z: boolean; constructor(x: string, y: string | number) { this.x = x this.y = y this.z = false } } var bar: Bar = new Bar('hello', 4) var obj: { a: string, b: number, c: Array<string>, d: Bar } = { a: 'hello', b: 11, c: ['hello', 'world'], d: new Bar('hello', 3) } 

類的類型註釋格式如上,能夠對類自身的屬性作類型檢查,也能夠對構造函數的參數作類型檢查。這裏須要注意的是,屬性 y 的類型中間用 | 作間隔,表示 y 的類型便可以是字符串也能夠是數字。

對象的註釋類型相似於類,須要指定對象屬性的類型。

#Null

若想任意類型 T 能夠爲 null 或者 undefined,只需相似以下寫成 ?T 的格式便可。

/*@flow*/ var foo: ?string = null 

此時,foo 能夠爲字符串,也能夠爲 null

目前咱們只列舉了 Flow 的一些常見的類型註釋。若是想了解全部類型註釋,請移步 Flow 的官方文檔

#Flow 在 Vue.js 源碼中的應用

有時候咱們想引用第三方庫,或者自定義一些類型,但 Flow 並不認識,所以檢查的時候會報錯。爲了解決這類問題,Flow 提出了一個 libdef 的概念,能夠用來識別這些第三方庫或者是自定義類型,而 Vue.js 也利用了這一特性。

在 Vue.js 的主目錄下有 .flowconfig 文件, 它是 Flow 的配置文件,感興趣的同窗能夠看官方文檔。這其中的 [libs] 部分用來描述包含指定庫定義的目錄,默認是名爲 flow-typed 的目錄。

這裏 [libs] 配置的是 flow,表示指定的庫定義都在 flow 文件夾內。咱們打開這個目錄,會發現文件以下:

flow
├── compiler.js        # 編譯相關
├── component.js       # 組件數據結構
├── global-api.js      # Global API 結構
├── modules.js         # 第三方庫定義
├── options.js         # 選項相關
├── ssr.js             # 服務端渲染相關
├── vnode.js           # 虛擬 node 相關

能夠看到,Vue.js 有不少自定義類型的定義,在閱讀源碼的時候,若是遇到某個類型並想了解它完整的數據結構的時候,能夠回來翻閱這些數據結構的定義。

#總結

經過對 Flow 的認識,有助於咱們閱讀 Vue 的源碼,而且這種靜態類型檢查的方式很是有利於大型項目源碼的開發和維護。相似 Flow 的工具還有如 TypeScript,感興趣的同窗也能夠自行去了解一下。

相關文章
相關標籤/搜索