Flow 是一个静态类型检查器,可以在编码时识别问题并快速反馈,它专门为 JavaScript 程序员设计,能够理解常用的 JS 语言及其动态特性,开发时Flow 会给出错误类型提示,但是他不会禁止代码运行
# 全局安装
npm install -g flow-bin
// @flow
标识[ignore] # 忽略的不需要检查的文件
<PROJECT_ROOT>/node_modules/.*
# <PROJECT_ROOT> 表示根目录的绝对路径
[include] # 表示待检测的路径, .flowconfig 所在目录下的所有文件都被认为是待检测的
[libs] # 指定接口文件的路径
src/interfaces/
[lints]
[options] # 设置配置项
module.name_mapper='^.*\.less$' -> 'css-module-flow' # 解决flow查找样式出错
[strict]
代码第一行加上 // @flow 的注释,这样 flow 就会检查这个文件了
// @flow
:
开头,可以用在方法参数和返回值还有变量声明// @flow
// any 注解表示任意动态类型
function foo(x: number, y: string, z: Array<number | string | Array<any>>): number | null {
return x * 10 * y .length + z.length;
}
const a = foo(21, '1sss0', [2, 3, 'ssss', ['s']]);
const b: number = 1234;
class Test {
a: string = 'test a';
static b: number = 0;
showArray(a: number): Array<any> {
return [a, this.a];
}
}
const test = new Test();
const res = test.showArray(Test.b);
console.log(a, b, res);
修改注解为如下,弱模式一样会给出类型错误,但是会给的更少或者更易修复
// @flow weak
接口文件,Flow 支持接口文件,目的是帮助 Flow 理解第三方的代码,这些文件定义了一个第三方模块的的接口,包括类型,他同时又跟第三方源码分离,不需要改变第三方文件,接口文件只是用来定义类型检查
[ignore]
[include]
[libs] # 引入需要的接口文件
src/interfaces/
[lints]
[options]
module.name_mapper='^.*\.less$' -> 'css-module-flow'
[strict]
declare var DEBUG: bool; // 声明一个全局变量类型
declare function isLeapYear(year: string): bool; // 全局函数
// 声明模块由命名模块和声明导出模块组成,导出的可以是变量、函数、类等
declare module Misc {
declare var DEBUG: bool;
}
declare module 'immutable' {
declare var exports: $Exports<'immutable'>;
}
JavaScript 原生数据类型, Flow 基本都有,但是可以使用小写,例如:js 中 Number flow 中 number, 如果使用 Number 这类 表示传入的值要是一个 Number 类型的对象,如果传入的是数值会报错,如果使用 number 则传入 数值即可
可以使用
|
表示或者 使用&
表示并且
可以通过?
定义可选值,如下
function test(a: ?string, b?: number) {
// a: ?string 表示属性值不一定是 string 也可以是 null undefined
// b?: number 表示属性可有可无
}
flow 支持对 es6 的类进行标注,包括类的属性和方法,类中的属性必须额外添加类型标注,并且要与方法同一层
// @flow
class P {
name: number; // 类中的属性需要在与方法同一级添加类型标注
constructor(name) {
this.name = name;
}
}
class Parent {
name: string;
constructor(name: string) {
this.name = name;
}
}
class Child extends Parent {
constructor(name) {
super(name);
}
}
const c: Parent = new Child('sss'); // 使用类判断类型
console.log(c.name);
如果 两个 class 的结构类似,那么对应的实例如果想在类型判断时为相同,那么可以使用 interface 声明一个接口
// @flow
interface PP {
name: string;
read(): string;
}
class P {
name: string;
constructor(name: string) {
this.name = name;
}
read(): string {
return this.name;
}
}
class Parent {
name: string;
constructor(name: string) {
this.name = name;
}
read(): string {
return this.name;
}
}
const p: PP = new Parent('sss');
console.log(p.read());
// type 定义的类型不仅可以是对象,也可以是数组或者字符串等
type Parent = {
name: string,
age: number
}
const p: Parent = {
name: 'xxx',
age: 90
};
// 无状态组件
const Button = (props: {text: string}) => (<button>{props.text}</button>)
// 一般组件
// 定义 Props 类型
type Props = {
changeInputInfo: Function,
inputInfo: Map<string, any>,
postNewInfo: Function
}
type State = {
test: number
}
export default class NewMember extends React.PureComponent<Props, State> {
// 挂在到 this 下的属性要在这里提前声明类型
state: State;
constructor(props: Props) {
super(props);
this.state = {
test: 0
};
}
handleChange(mold: string, e: any): void {
const { changeInputInfo, inputInfo } = this.props;
const newInfo = inputInfo.set(mold, e.target.value);
changeInputInfo(newInfo);
}
handleClick = () => {
const { postNewInfo, inputInfo } = this.props;
postNewInfo(inputInfo)
.then(res => console.log('success return ', res))
.catch(err => console.error(err));
};
render(): React.Element<any> {
const inputInfo = this.props.inputInfo;
const test = this.state.test;
return (
<div className="new-member">
<p>
姓名:
<input type="text" value={inputInfo.get('name')} onChange={this.handleChange.bind(this, 'name')} />
</p>
<p>
电话:
<input type="tel" value={inputInfo.get('tel')} onChange={this.handleChange.bind(this, 'tel')} />
</p>
<button onClick={this.handleClick}>提交 {test}</button>
</div>
);
}
}