Flow 快速上手

1,077 阅读6分钟

什么是 Flow

Flow 是 javascript 的类型检查器, 是 14年由 facebook 推出的一款工具, 使用它可以弥补弱类型带来的弊端. 在一些大型项目中我们也可以经常见到 flow 的身影, 到现在, flow 已经是一款很成熟的js类型检查工具了.
flow 原理就是在代码中加一些类型注解的方式表明变量或者参数是什么类型的. flow就会根据类型注解发现代码中的一些异常, 从而避免在运行时才发现这些问题. 例如下面的代码

function sum (a: number, b: number) {
  return a + b
}

sum(100, 100)

sum('100', '100')

sum 函数中声明的 a: number, number就是类型注解, 调用 sum(100, 100)是正常点, 但是 如果调用sum('100', '100') 在编辑器中就会爆红,使得我们及时发现问题.

快速上手

首先在命令行执行以下命令

yarn init -y // 初始化 package.json
yarn add flow-bin --dev  // 安装 flow

然后新建一个js文件,书写如下代码,

image.png

首先 要使用 flow, 在文件开头必须 写一个 标记 // @flow ,然后我们给函数限制 a,b都为 number,这个时候发现还没等 flow工作,编辑器就爆红了, 因为 这不是 javascript 标准语法, 我们只要关掉js默认校验使用flow 校验.
具体步骤就是打开编辑器设置,搜索 javascript validate, 关掉第一个选项即可,这个时候返回再看代码发现就没有报错了

image.png 接下来终端执行如下命令创建一个 .flowconfig文件

yarn flow init

然后执行 命令

yarn flow

得到如下结果,可以清晰的看到 调用sum时不应该传入string而是传入 number image.png

移除类型注解

因为 加了类型注解的代码不是标准js代码,不能执行,所以我们需要知道如何将之移除,这里我们安装一个模块 并执行

yarn add flow-remove-types --dev
// 执行     . 当前目录 输出 dist目录
yarn flow-remove-types . -d dist

接着我们到 dist目录就会找到这个文件,并且里面的代码是移除了类型注解的

function sum(a        , b        ) {
  return a + b;
}
sum(100, 200);
sum('100', 200);

当然我们还可以用 babel插件的方式来移除代码,具体就是,安装babel相关包

yarn  add @babel/core @babel/cli @babel/preset-flow --dev
// 执行, 这里我们将代码首先放入src文件
yarn babel src -d dist

得到的结果是一样的

flow插件

因为上述代码中我们是无法看到那里报错,必须运行一遍才能呢发现,所以就有了 flow 插件.安装图中第二就行

image.png

安装完成之后我们回到代码就会发现会有报错,这样就更直观的看到了,但是这个需要保存之后才能有报错提示.

image.png

类型推断

如下图片上我们可以看到, 我们没有给 n 加类型注解,但是当你调用的时候传入字符串就会报错, 因为flow推断出 相乘的两个数肯定只有数字于数字才行

image.png

flow 原始类型

这里我们列出来了, 这里对 每个类型做了限制,那么就不能随意切换类型

const a: string = 'foobar'

const b: number = Infinity // NaN // 100

const c: boolean = false // true

const d: null = null

const e: void = undefined

const f: symbol = Symbol()

flow 数组类型

可以有两种方式表示数组类型, 一个是泛型的方式,还有一个就是正常的表示方式

const arr1: Array<number> = [1, 2, 3]

const arr2: number[] = [1, 2, 3]

当然如果要传入固定长度的数组,可以这样写, 这种数据结构有个更专业点名称叫元组

const arr3: [string, number] = ['aa', 1]

flow 对象类型

通过 在大括号中限制每个属性来限制对象, 属性后面有个 ? 代表该属性可有可无, 没有问号就代表一定要有该属性,并且属性的类型要按照定义的来,否者报错

const obj1: { foo: string, bar: number } = { foo: 'lalala', bar: 100 }

const obj2: { foo?: string, bar: number } = { bar: 100 }

如果我们想给对象添加任意个数类型的键可以这样

const obj3: { [string]: string } = {};

obj3.key1 = 'value1';
obj3.key2 = 'value2';

这里我们限制了 obj3 只要 键和值的类型都是字符串就可以不限制传入个数

flow 函数类型

函数类型主要就是限制 传递的参数 以及返回值的类型, 现在参数类型就是 在参数后面写上类型注解,限制返回值类型,就在函数括号后面添加相应的类型注解, 如果函数作为参数又该如何限制呢?
比如下面的一个函数

function foo (callback) {
  callback('string', 100)
}

那么我们应该这样

// 传入的 是一个函数, 有两个参数,分别为 string和number, 并且是 void,也就是没有返回值
function foo(callback: (string, number) => void) {
  callback('string', 100);
}

flow 特殊类型

1. 字面量类型 我们可以自定义类型,但是值只能是对应类型的值,比如

const a: 'foo' = 'foo'

a 的类型是 foo, 那么值也只能是foo,否者报错. 这个有什么用呢? 我们一般用来限制 某个变量为某几个值中的一个.比如:

const type: 'success' | 'warning' | 'danger' = 'success'

2. Maybe类型

const gender: ?number = undefined

就如上面展示, 在类型前面加个 问号 代表 number类型可以为 underfined和null

flow中 Mixed 和 any类型

Mixed 和 any 都可以传入任意类型,比如:

function passMixed (value: mixed) {

}

passMixed('string')
passMixed(100)

function passAny (value: any) {

}
passAny('string')
passAny(100)

那么它们之前有什么区别的, mixed实际上还是强类型语言, any是弱类型.

image.png

我们在 passMixed 使用 value会报错, 因为不明确 value 类型 是不能直接调用,如果需要使用我们只能通过判断的方式去使用,这样的话使用 value 还是安全的,如下代码

function passMixed(value: mixed) {
  if (typeof value === 'string') {
    value.substr(1);
  }

  if (typeof value === 'number') {
    value * value;
  }
}

any类型怎么写都不会报错,,,所以any类型会有很多安全隐患

总结

这里我们只是简单了解了 flow 常见类型, 还有其他很多类型可以看 flow官网 ,学习 flow 目的在我看来是为了 防止在某些大型项目中有flow, 我们可以读懂其中的代码.