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”或扫描下面的二维码

相关文章
相关标签/搜索