flow的使用 | 掘金技術徵文

做者:滴滴公共前端團隊 - Jjavascript

前言:

不少人都開始一上來就應用到了 Vue.js 2.*,但並非全部人都會發覺 Flow 的存在,其實熟悉 react 源碼的應該不會陌生。因此呢,今天咱們來普及一下這個東西到底對咱們的工程成本有什麼收益呢?
它和 Babel 還有咱們內部經常使用的 ESlint 有什麼插件支持?
它和 Crockford 的 JSLint 或者後面的 JSHint 有什麼區別?html

正文:

facebook 推出的 js 靜態類型檢查工具。前端

flow能夠在代碼運行前對類型錯誤進行檢查,包括:java

  • 類型錯誤
  • 對null的引用
  • 以及可怕的 「undefined is not a function」
    flow 容許咱們給變量添加類型

flow 的安裝和使用

安裝:
因爲 flow 是用 OCaml 語言寫的,npm 上只有對應的二進制包。react

npm install --save-dev flow-bin複製代碼

1.基本使用git

安裝完成後咱們在要執行靜態檢查的文件跟目錄下執行一下 flow init ,以後會發現多處一個.flowconfig文件,這個文件告訴 Flow 在這個目錄下開始檢測。此外 .flowconfig 文件能夠進行一下更爲高級的配置,好比僅包含一些目錄、忽略一下目錄等等(更深刻的瞭解,請戳官網)。 github

對於須要使用 flow 進行類型檢查的 js 文件,在開頭加入 @flow 的註釋shell

/* @flow */ 只要帶有這個註釋,都會進行類型檢測

或者

/* @flow weak */ 只對有加類型註解的變量進行類型檢測複製代碼

例如:npm

/* @flow */
function multiple10 (num) {
  return num * 10
}

multiple10('20')

function getLength (str) {
  return str.length
}
getLength('3')
getLength([1,2,3])複製代碼

接下來執行 flow check 看一下結果json

3: return num * 10
          ^^^ string. The operand of an arithmetic operation must be a number.

Found 1 error複製代碼

multiple10 函數中的類型轉換被 flow 標記出。

2.類型註解

注意上面例子中 flow 的報錯,只有 multiple10 中靜態類型錯誤被檢測中。對於 getLength 函數中參數 str 的類型是什麼呢? 從函數自己來分析,只要包含 length 屬性就都是合法的。 對於這種狀況則能夠爲其添加「類型註解」,來明確的告訴 flow 這個值的類型。

function getLength (str: string) {
  return str.length
}
getLength('3')
getLength([1,2,3])複製代碼

再來運行一下 flow check , 這時結果會提示咱們[1,2,3]這個參數類型不對。

12: getLength([1,2,3])
               ^^^^^^^ array literal. This type is incompatible with the expected param type of
  8: function getLength (str: string) {
                              ^^^^^^ string複製代碼

3.自定義類型

不少時候,除了 number 、 string 這些基礎類型外,咱們還會有一些自定義的類型,好比:

var someData = {
    id: 1,
    text: '選項1'
}複製代碼

這時候能夠在一個單獨的文件中將 someData 申明瞭一個自定義類型。方式以下:

/* /decls/data.js.flow */
declare type SomeData = {
  id: number;
  text: strin;
}複製代碼

而後在 .flowconfig 文件中引入該申明文件

[libs]
decls/複製代碼

flow server

在大型項目中,若是每修改完代碼,就執行如下 flow check ,而後等待看結果,顯然會被逼瘋的。flow 爲咱們提供了一個 flow server ,支持在後臺運行,而且只監測有修改的文件。方法很簡單,只有一個命令

$> flow # 開啓一個後臺服務,輸出首次檢測結果
$> flow # 第二次使用flow,鏈接正在運行的後臺服務,輸出檢測結果
$> flow stop # 關閉flow server複製代碼

babel+flow

因爲 flow 中類型註解的語法不屬於 javascript 規範中的內容。因此在最終的代碼中,咱們須要移除flow的內容。flow 提供了 flow-remove-types 和 babel 插件兩種方式,推薦使用 babel 插件來完成這項工做。

  • flow-remove-types
    這種方法比較簡單粗暴: 安裝 flow-remove-types,而後執行命令。

    $> npm install -g flow-remove-types
    $> flow-remove-types src/ --out-dir build/複製代碼
  • babel插件
    安裝 babel 插件

    $> npm install babel-plugin-transform-flow-strip-types複製代碼

    babel 的 plugin 中加入該插件

    {
    "presets": ["es2015", "stage-2"],
    "plugins": ["transform-runtime", "transform-flow-strip-types"],
    "comments": false
    }複製代碼

    注意:在 babel6 的 babel-preset-react 的插件中已經內置了 transform-flow-strip-types(flowtype.org/docs/syntax…),若是使用了 babel-preset-react 那麼無需再引入transform-flow-strip-types

eslint

eslint-plugin-flowtype 插件,可讓咱們在 eslint 代碼檢查中加入 flow 的書寫規範化檢查。使用方式也很簡單:

  1. 安裝

    $> npm install eslint-plugin-flowtype複製代碼
  2. 在 .eslintrc.js 中設置 parser 爲 babel-eslint
  3. plugin 中加入 flowtype
  4. eslint-plugin-flowtype 插件中默認提供了一份基於優秀實踐總結出的 flow type 書寫規範配置,在 .eslintrc 文件的 extend 中加入 "plugin:flowtype/recommended" 便可直接使用。
{
  "extends": [
    "standard",
    "plugin:flowtype/recommended"
  ],
  "plugins": [
    "flowtype"
  ]
}複製代碼

完成後咱們來看看效果。下面的代碼

function getLength (str:string) {
  return str.length
}
getLength('3')複製代碼

eslint 檢查結果會拋出一個錯誤:類型註解的冒號後面丟失了空格。

✘  https://google.com/#q=flowtype%2Fspace-after-type-colon  There must be a space after "str" parameter type annotation colon
  /Users/didi/xiaoju/src/static-h5-src/750/driver/feedback/src/main.js:2:21
  function getLength (str:string) {
                       ^
✘ 1 problem (1 error, 0 warnings)複製代碼

由於推薦的規範中:類型註解冒號後須要一個空格

"rules": {
   ...
    "flowtype/space-after-type-colon": [
      2,
      "always"
    ],
    ...
 }複製代碼

flow type 規範配置如:函數返回類型是否必須、類型註解冒號先後的空格、自定義的type 的名稱的命名方式等等,官方給出了很詳細說明和例子。注:針對flow的的規範規則配置前添加「flowtype/」

配置名稱 做用
boolean-style 類型註解中布爾值使用boolean仍是bool
define-flow-type 將類型註解標記爲已定義,no-undef的檢查中不會出現報錯
delimiter-dangle Object和Tuple類型定義中分隔符使用規範
generic-spacing 泛型對象的尖括號中類型先後的空格規範
space-before-generic-bracket 泛型對象的尖括號前的空格規範
no-dupe-keys object類型的定義中是否有重複的屬性值
no-primitive-constructor-types 禁止使用原生的類型
no-weak-types 是否可使用弱類型any、Object、Function
object-type-delimiter Object類型定義中,屬性以前分割符爲分號/逗號(注:該屬性已被廢棄,須要使用分號來分割)
require-parameter-type 函數的參數是否須要類型註解
require-return-type 函數返回值是否須要類型註解
require-valid-file-annotation 文件開頭@flow的寫法
require-variable-type 什麼樣的變量是須要類型註解
semi 使用type自定義類型語句結尾是否須要分號結尾
sort-keys Object類型定義中屬性排列順序
space-after-type-colon 類型註解分號後的空格規範
space-before-type-colon 類型註解分號前的空格規範
type-id-match 使用type自定義類型的名稱規範
union-intersection-spacing union類型、intersection類型鏈接符號\ 、&之間的空格規範
use-flow-type 將經過declare定義的自定義類型標記爲已經被使用過,no-unused-vars的檢查中不會出現報錯
名詞說明

文中一些中文詞直接從英文文檔中翻譯過來,可能有不許確的地方,這裏給出原文,避免歧義。

  • 類型註解:原文爲 type annotations ,標記變量的類型
  • 自定義類型:原文爲 type aliases, 相似C語言中的typedef,能夠爲已有類型定義一個新的名稱,或將一個複雜類型進行封裝,如

    type a = Array<String>
    type Person = {
       name: string,
       age: number
    };複製代碼
相關連接

flow 官網(關於 flow的各類用法官網給出了詳細的例子):flowtype.org/
flow 簡短教程:www.youtube.com/watch?v=xWM…

「掘金技術徵文」活動:gold.xitu.io/post/58522d…


歡迎關注DDFE
GITHUB:github.com/DDFE
微信公衆號:微信搜索公衆號「DDFE」或掃描下面的二維碼

相關文章
相關標籤/搜索