前言
FLOW IS A STATIC TYPE CHECKER FOR JAVASCRIPT.
JavaScript 作为一种动态类型语言,有它自己的灵活性,这很好。
但近些年来,随着前端领域的快速发展,这种灵活性对于大型的应用场景来说,反而成为一种负担。
一旦代码变得非常庞大,值的类型不固定将不利于代码的维护和迭代。
为了解决这个问题,我们是需要对代码做类型的注解(或者说标注),确保开发者明确代码逻辑,避免不必要的错误。
当然这些注解只是在开发时被开发者看到,在打包成生产代码后,就不需要注解了,因为 ECMAScript 标准中并不能识别这些类型注解。
Flow 通过类型注解来检查代码,保证代码中值类型的准确和稳定,提高性能,便于维护。
一、Flow 的使用
- 新建文件夹并进入,初始化 package 文件,
yarn init --yes
- 添加 flow 命令,
yarn add flow-bin --dev
// @flow function sum (a: number, b: number) { return a + b; }
这样写时,vscode 会默认检查 js 语法,a 和 b 不合法。解决办法:关闭 JavaScript Validate
- 关闭 JavaScript Validate,文件 > 首选项 > 设置 > 输入框中输入:javascript validate > 取消勾选
- 启动 flow ,检查类型,
yarn flow
(注意:在此之前需要生成一个 flow 的配置文件,yarn flow init
) - 在终端中启动,
yarn flow
来检查类型,终端中可以看到结果报告。(如果发生错误,它会在终端处打印结果;如果没有错误,它会告诉你 No errors!)
二、自动移除源码中的类型注解
方案一: Flow
yarn add flow-remove-types --dev
yarn flow-remove-types ./src -d dist
(./src 是需要检查文件所在目录,dist 是移除类型注解后的打包文件所在目录。)
方案二:Babel
yarn add @babel/core @babel/cli @babel/preset-flow --dev
- 根目录下添加配置文件,
.babelrc
// .babelrc { "presets": ["@babel/preset-flow"] }
- 运行命令,
yarn babel src -d dist
三、类型检测插件
以下有两个插件可以实现在编写代码时就会实时检测并提示,不用编译。这里推荐第二个插件,第一个刚刚实测无效。
- Flow Language Support
- vscode-flow-ide
在 vscode 插件库中查找并安装,尝试写一个错误的案例,插件会有提示错误。
四、类型检测
1. 类型注解
/* * 类型注解 * @flow */ // 参数类型注解 function square (n: number) { return n * n; } // 变量类型注解 let num: number = 100; // num = '100'; // 函数返回值类型注解 function foo (): number { return 100; // return '100'; } // 函数没有返回值默认返回 undefined,类型注解为 void function bar (): void { }
2. 原始类型
/* * 原始类型 * @flow */ const a: string = 'string'; const b: number = Infinity; // NaN // 100 const c: boolean = true; // false const d: null = null; const e: void = undefined; const f: symbol = Symbol();
3. 数组类型
/* * 数组类型 * @flow */ // Array<number> 表示这是一个全部由数字组成的数组 const arr1: Array<number> = [1, 2, 3]; const arr2: number[] = [1, 2, 3]; // 指定数组长度大小和类型 固定大小的数组叫做元组 const foo: [string, number] = ['', 123];
4. 对象类型
/* * 对象类型 * @flow */ const obj1: { foo: string, bar: number } = { foo: 'str', bar: 123 } // foo 成员可选 const obj2: { foo?: string, bar: number } = { bar: 123, // kk: '123' } // 控制键值类型 const obj3: { [string]: string } = {}; obj3.key1 = 'value1'; obj3.key2 = 'value2'; obj3.key3 = 'value3';
5.函数类型
/* * 函数类型 * @flow */ function foo (cb: (string, number) => void) { cb('string', 100); } foo(function (str, n) { // })
6.特殊类型
/* * 特殊类型 * @flow */ const a: 'foo' = 'foo'; // 联合类型 const type: 'success' | 'warning' | 'danger' = 'success'; type StringOrNumber = string | number; const b: StringOrNumber = 'string'; // ---------------------------- // maybe 类型 const gender: ?number = undefined; // 等价于 const gender2: number | void | null = undefined;
7.任意类型
/* * 任意类型 mixed any * @flow */ // mixed 强类型 function passMixed (value: mixed) { if (typeof value === 'string') { value.slice(1) } if (typeof value === 'number') { value * value } } passMixed('str'); passMixed(123); // any 弱类型 (兼容老语法) function passAny (value: any) { value.slice(1) value * value } passAny('str'); passAny(123);