第二种方式,不需要任何代码修改即可进行类型检查,最小化开发者的工作量。它不会强制你改变开发习惯,因为它会自动推断出变量的类型。这就是所谓的类型推断,Flow最重要的特性之一。
我们来通过一个例子来说明这个特性:
/*@flow*/ function foo(x) { return x.split(' '); } foo(34);
当你在终端运行npm run flow命令的时候,上述代码会报错,因为函数foo()的期待参数是字符串,而我们输入了数字。错误信息类似如下:
index.js:4
4: return x.split(' ');
^^^^^ property `split`. Property not found in
4: return x.split(' ');
^ Number
上述信息清楚地指出了出错位置和错误原因。我们只要将参数变成字符串,即可修正错误。该例想说明的是,因为split()方法只适用于string类型的变量,所以x应该是string,这就是类型推断。
四、空类型
Flow处理null的方式与其他类型库不同。它不会忽略null,这样可以防止了因给变量传了null而导致程序崩溃的错误。
/*@flow*/ function stringLength (str) { return str.length; } var length = stringLength(null); Flow会报错。为了防止出错,我们需要单独处理null。 /*@flow*/ function stringLength (str) { if (str !== null) { return str.length; } return 0; } var length = stringLength(null);
代码中我们引入对null的检查,确保代码能在任何情况下都正常且正确运行。上述代码可以通过Flow的类型检查。
五、类型注释
如上所述,类型推断是Flow最有用的特性之一,不需要编写类型注释就能获取有用的反馈。但在某些特定的场景下,添加类型注释可以提供更好更明确的检查依据。考虑以下代码:
/*@flow*/ function foo(x, y){ return x + y; } foo('Hello', 42);
Flow检查上述代码时检查不出任何错误,因为+即可以用在字符串上,也可以用在数字上,我们并没有明确指出add()的参数必须为数字。
在这种情况下,我们可以借助类型注释来指明期望的类型。类型注释是以冒号:开头,可以在函数参数,返回值,变量声明中使用。如果我们在上段代码中添加类型注释,就会变成如下:
/*@flow*/ function foo(x : number, y : number) : number { return x + y; } foo('Hello', 42);
现在Flow就能检查出错误,因为函数参数的期待类型为数字,而我们提供了字符串。Flow报错信息类似如下:
index.js:7
7: foo('Hello', 42);
^^^^^^^ string. This type is incompatible with the expected param type of
3: function foo(x : number, y : number) : number{
^^^^^^ number
如果传入的参数是数字,就不会有错误。类型注释在大型复杂的JavaScript文件中也很有用,它能保证代码按照预期进行。
六、Flow能支持的其他更多类型注释。
其实说到底就是类似java那种强语言类型的写法,给每个变量声明是什么类型,给每个函数声明返回值类型,给每个数组元素声明类型等,就是仿造java的写法,哈哈,java传值不对时就会给你报错一样的道理
1、函数
/*@flow*/ function add(x : number, y : number) : number { return x + y; } add(3, 4);
上述代码展示了变量类型注释以及函数类型注释。函数add()的参数,以及函数的返回值,期待类型为数字。如果传入其他类型参数,Flow就会检测到错误。
2、数组
var foo : Array<number> = [1,2,3];
数组类型注释的格式是Array<T>,T表示数组中每项的数据类型。在上述代码中,foo是每项均为数字的数组。
3、类
下面展示了类和对象的类型注释模型。唯一需要注意的是,可以在两个类型之间使用或逻辑,用|来间隔。变量bar1添加了必须为Bar类的类型注释。
class Bar{ x:string; // x should be string y:string | number; // y can be either a string or a number constructor(x,y){ this.x=x; this.y=y; } } var bar1 : Bar = new Bar("hello",4);
4、对象字面量
对象的类型注释类似于类,指定对象属性的类型。
var obj : {a : string, b : number, c: Array<string>, d : Bar} = { a : "hello", b : 42, c : ["hello", "world"], d : new Bar("hello",3) }
5、Null
若想任意类型,T可以为null或者undefined,只需类似如下写成 ?T 的格式即可。
/*@flow*/ var foo : ?string = null;
此时,foo可以为字符串,也可以为null。
目前我们只对Flow的类型注释做了很浅的探索。一旦你习惯了使用这些基本类型,建议在Flow官网上的类型文档深入了解所有的类型。
七、库定义
我们经常需要引入第三方库,Flow检查时就会抛出错误。但这并不是我们期待的错误。
庆幸的是,我们不需要修改库源码去防止这些报错。我们只需创建一个库定义(libdef)。libdef是包含第三方库声明的JS文件简称。观察下面的例子: