五个简单例子
在接下例子里,我们将用 flow 命令行来检查代码。
你可以使用 npm 运行
npm install --global flow-bin
从而安装命令行工具
译者:安装略坑,建议
- mac: brew install flow
- linux: 如果 npm install 不好使就自己到 github 下源码按照提示 make
- windows: 官方都没提太多,参考 这里
第一次运行 flow 通常会多花几秒,接下来每次都会快一点。
这是因为运行 flow 会启动一个后台进程,
监测你当前项目,当你每次修改保存后,自动重新计算类型错误。
可以使用 flow stop 来停止这个后台进程
如果你只是想检查一下,而不要一个后台进程,
(你不介意每次都多等几秒的话)那么你可以使用 flow check命令。
这样的话,Flow 在检查完你的项目后就立即停止了。
1. Hello Flow!#
在 Flow GitHub 库里, 你可以找到
examples 目录.
这个目录包含了教程所需的例子。先看看第一个例子,感受一下 Flow
$> cd flow/examples/01_HelloWorld
$> flow
你应该看到如下错误:
hello.js:7
  7: foo("Hello, world!");
     ^^^^^^^^^^^^^^^^^^^^ function call
  4:   return x * 10;
              ^ string. This type is incompatible with
  4:   return x * 10;
              ^^^^^^ number
看下例子中的 hello.js 文件, 就明白为什么了:
| 1 2 3 4 5 6 7 8 9 | // @flow (function() { function foo(x) { return x * 10; } foo('Hello, world!'); }); | 
我们调用 foo 方法,使用 string 类型参数,不过 foo 方法期望的参数是 number 类型的。
Flow 能够检测到这个问题并且给出错误提示。解决这个错误的一个方案就是调用 foo 时用
number 类型参数
// @flow这个注释很关键:它告诉 Flow 这个文件需要检测。 如果某些文件不带这个注释,Flow 则会忽略检测这些文件
2. Add type annotations(类型注释 / 类型注解)#
在大多数情况下,Flow 都能够探测出具体类型,所以你不需要给每个方法、变量都添加类型注解。 虽说 Flow 能探测出类型,但是你依然可以严格声明类型。 只有下面这类情况才 必须 明确地声明类型:变量/方法/类 是从别的模块中导入的(在别的文件定义)
第二个例子 (02_TypeAnnotations) 展示 Flow 简单的类型注释:
| 1 2 3 4 5 6 7 8 9 | // @flow (function() { function foo(x: string, y: number): string { return x.length * y; } foo('Hello', 42); }); | 
这表示 foo 方法返回值的类型为 string,并且两个参数类型分别为 string 和 number
有了这些类型注释之后,如果运行 flow check 将会看到如下错误提示:
type_annotations.js:4
  4:   return x.length * y;
              ^^^^^^^^^^^^ number. This type is incompatible with the expected return type of
  3: function foo(x: string, y: number): string {
                                         ^^^^^^ string
此时提示 foo 返回值的类型有误。我们声明了返回值为 string 类型,
可是返回的(number)不匹配,于是 Flow 就给出错误提示,可以通过修改返回类型来解决
| 1 2 3 4 5 6 7 8 9 10 | // @flow (function() { // Changing the return type to number fixes the error function foo(x: string, y: number): number { return x.length * y; } foo('Hello', 42); }); | 
3. Nullable types#
Flow 处理 null 的方式跟大多数类型系统不太一样。如果检测工具没有仔细地跟踪好 null 的使用,
  那么可能会误导你,让你认为你的代码都没问题了,于是在非法使用 null 的时候就悲剧了。
当 Flow 检测到你访问 null 的方式存在危险的话,
  它就会给你错误提醒,正如第三个例子(03_Null)
| 1 2 3 4 5 6 7 8 9 | // @flow (function() { function length(x) { return x.length; } var total = length('Hello') + length(null); }) | 
这个程序在运行时会报 TypeError 错误,因为读取 null 的 length 属性是不合法的.
运行 flow 能够提前检测出这个 bug:
nulls.js:7
  7: var total = length("Hello") + length(null);
                                   ^^^^^^^^^^^^ function call
  4:   return x.length;
                ^^^^^^ property `length`. Property cannot be accessed on possibly null value
  4:   return x.length;
              ^ null
answer 目录里的代码给出了解决方案,也许你在运行代码发现错误后也会这么解决。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | // @flow (function() { function length(x) { if (x !== null) { return x.length; } else { return 0; } } var total = length('Hello') + length(null); }); | 
因为我们已经判断 x 是非 null,Flow 知道现在的代码是安全的,然后就不会出现错误提醒了。
4. Arrays (数组)#
当然,Flow 能检测的类型不仅仅是数字和字符串,下一个例子 04_Arrays,展示如何在函数中
  对数组类型进行注解:
| 1 2 3 4 5 6 7 8 9 10 11 | // @flow function total(numbers: Array<number>) { var result = 0; for (var i = 0; i < numbers.length; i++) { result += numbers[i]; } return result; } total([1, 2, 3, 'Hello']); | 
Flow 会标注 'Hello' 字符串,因为 total() 方法只接受数字组成的数组
arrays.js:11
 11: total([1, 2, 3, "Hello"]);
     ^^^^^^^^^^^^^^^^^^^^^^^^^ function call
 11: total([1, 2, 3, "Hello"]);
                     ^^^^^^^ string. This type is incompatible with
  3: function total(numbers: Array<number>) {
                                   ^^^^^^ number
如果把 "Hello" 改为数字,就能通过 Flow 的检测
| 1 2 3 4 5 6 7 8 9 10 11 | // @flow function total(numbers: Array<number>) { var result = 0; for (var i = 0; i < numbers.length; i++) { result += numbers[i]; } return result; } total([1, 2, 3, 4]); | 
5. Dynamic code (动态代码)#
最后一个例子 05_DynamicCode,这里我们没有给函数返回类型注释类型,
  但是我们在调用的时候传递了两个不同类型的参数:
| 1 2 3 4 5 6 7 8 9 | // @flow (function() { function foo(x) { return x.length; } var res = foo('Hello') + foo(42); }); | 
这种情况,Flow 检测到第二次调用的参数是数字,它木有 length 属性,铁定会挂
dynamic.js:4
  4:   return x.length;
                ^^^^^^ property `length`. Property not found in
  4:   return x.length;
              ^ Number
一个简单的解决方式就是作类型判断:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 | // @flow (function() { function foo(x) { if (typeof x === 'string') { return x.length; } else { return x; } } var res = foo('Hello') + foo(42); }); | 
Flow 很聪明,能够明白你的条件语句规避了潜在的悲剧,于是就啥错误都没了。
下一步#
这些浅显的例子算是扒开了 Flow,以后在新项目就可以玩 Flow,然后在发布生产前用 转换工具 编译类型注解。 当然,你也可以 给老项目用上 FLow。 你还可以看看这个稍微大点的 React 例子,了解更多典型的用法
You can edit this page on GitHub and send us a pull request!