前言
关于Flow
Flow是Facebook出品的,针对JavaScript的静态类型检查工具。其代码托管在github上,并遵守BSD开源协议。
它可以帮助我们捕获JavaScript开发中的常见错误,而不需要额外地修改你原有的代码,比如静态类型转换,空值引用等问题。
同时,Flow为JavaScript添加了静态类型的语法标识,这样开发者便可以明确代码中的类型,让其自动地被Flow所维护。
为什么要先学Flow
因为Vue.js源码里使用了Flow作为静态代码检查工具,那为什么要用Flow呢?看看作者在知乎的回答:
2018 年,随着 TS 和 VSCode 的各种进化,现在确实比 Flow 好用很多了。下个版本用 TS 了,哈哈哈
这个选择最根本的还是在于工程上成本和收益的考量。Vue 2.0 本身在初期的快速迭代阶段是用 ES2015 写的,整个构建工具链也沿用了 Vue 1.x 的基于 ES 生态的一套(Babel, ESLint, Webpack, Rollup...),全部换 TS 成本过高,短期内并不现实。
相比之下 Flow 对于已有的 ES2015 代码的迁入/迁出成本都非常低:
- 可以一个文件一个文件地迁移,不需要一竿子全弄了。
- Babel 和 ESLint 都有对应的 Flow 插件以支持语法,可以完全沿用现有的构建配置;
- 更贴近 ES 规范。除了 Flow 的类型声明之外,其他都是标准的 ES。万一哪天不想用 Flow 了,用 babel-plugin-transform-flow-strip-types 转一下,就得到符合规范的 ES。
- 在需要的地方保留 ES 的灵活性,并且对于生成的代码尺寸有更好的控制力 (rollup / 自定义 babel 插件)第三点额外说一些:这一点上 Facebook 应该也是同样的考量,宁可贴近规范而不是用一个被 M$ 控制的、一旦使用难以迁出的语言。
为什么 Angular 就愿意用 TS 呢?因为 Angular 本来就是一帮搞 Java 的人弄出来的,而且只是 Google 的一个子项目,Google 在公司层面根本不关心它用什么语言。而对 Facebook 来说 React/ReactNative/Babel/Flow/Nuclide 是整个公司 infrastructure 层面的东西,要么依赖规范,要么就得自己有控制权。 编辑器 / IDE 方面,Atom + Nuclide 其实也还凑合,type warning / type hint / autocomplete / jump to definition 都有,就是 Atom 本身慢了点。
至于重构、设计什么的,我只想说,看的是使用的人的水平,跟用什么语言没那么大关系。水平烂的人用 TS 一样写的是翔一样的代码,看看 java 就知道了。 另外注意我并没有说 TS 不好,但是在 Vue 的需求和现状下 Flow 是更合理的选择。 https://www.zhihu.com/question/46397274/answer/101193678
Flow学习
官网学习:https://flow.org/en/docs/usage/
简介
Flow通过静态类型注释检查代码中的错误。这些类型允许您告诉Flow您希望代码如何工作,而Flow将确保它以这种方式工作。 可以使用 行注释和块注释:
// @flow
function square(n: number): number {
return n * n;
}
square("2"); // Error!
/* @flow */
function square(n) {
return n * n; // Error!
}
square("2");2
3
4
5
6
7
8
9
10
11
12
13
Flow会检查有@flow标记的文件或方法
Flow 的⼯作⽅式
通常类型检查分成 2 种⽅式:
- 类型推断:通过变量的使⽤上下⽂来推断出变量类型,然后根据这些推断来检查类型。
- 类型注释:事先注释好我们期待的类型,Flow 会基于这些注释来判断。
类型判断
它不需要任何代码修改即可进⾏类型检查,最⼩化开发者的⼯作量。它不会强制你改变开发习惯,因为它会⾃动推断出变量的类型。这就是所谓的类型推断,Flow 最重要的特性之⼀。
/*@flow*/``
function split(str) {
return str.split(' ')
}
split(11)2
3
4
5
Flow 检查上述代码后会报错,因为函数 split 期待的参数是字符串,⽽我们输⼊了数字。
类型注释
如上所述,类型推断是 Flow 最有⽤的特性之⼀,不需要编写类型注释就能获取有⽤的反馈。但在某些特定的场景下,添加类型注释可以提供更好更明确的检查依据。
/*@flow*/
function add(x, y){
return x + y
}
add('Hello', 11)2
3
4
5
Flow 检查上述代码时检查不出任何错误,因为从语法层⾯考虑, + 即可以⽤在字符串上,也可以⽤在数字上,我们并没有明确指出 add() 的参数必须为数字。
在这种情况下,我们可以借助类型注释来指明期望的类型。
类型注释是以冒号 : 开头,可以在函数参数,返回值,变量声明中使⽤
如果我们在上段代码中添加类型注释,就会变成如下:
/*@flow*/
function add(x: number, y: number): number {
return x + y
}
add('Hello', 11)2
3
4
5
现在 Flow 就能检查出错误,因为函数参数的期待类型为数字,⽽我们提供了字符串。
常见类型注释
上⾯的例⼦是针对函数的类型注释。接下来我们来看看 Flow 能⽀持的⼀些常⻅的类型注释。
全部注释查看官方文档:https://flow.org/en/docs/types/
数组
/*@flow*/
var arr: Array<number> = [1, 2, 3]
arr.push('Hello')2
3
数组类型注释的格式是 Array<T> , T 表⽰数组中每项的数据类型。在上述代码中,arr 是每项均为数字的数组。如果我们给这个数组添加了⼀个字符串,Flow 能检查出错误。
类和对象
class Bar {
x: string; // x 是字符串
y: string | number; // y 可以是字符串或者数字
z: boolean;
constructor(x: string, y: string | number) {
this.x = x
this.y = y
this.z = false
}
}
var bar: Bar = new Bar('hello', 4)
var obj: { a: string, b: number, c: Array<string>, d: Bar } = {
a: 'hello',
b: 11,
c: ['hello', 'world'],
d: new Bar('hello', 3)
}2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
类的类型注释格式如上,可以对类⾃⾝的属性做类型检查,也可以对构造函数的参数做类型检查。这⾥需要注意的是,属性 y 的类型中间⽤ | 做间隔,表⽰ y 的类型即可以是字符串也可以是数字。
对象的注释类型类似于类,需要指定对象属性的类型。
Null
若想任意类型 T 可以为 null 或者 undefined ,只需类似如下写成 ?T 的格式即可。
/*@flow*/
var foo: ?string = null2
此时, foo 可以为字符串,也可以为 null 。
总结
前端也有代码检查,虽然不像java可以在编写过程中就及时告诉你,但相比以前要方便很多。
静态代码检查还有个好处就是可以在检查过程中学习,为什么这个地方检查不通过,花几分钟研究会有很大的收获。