Flow快速了解及上手

564 阅读7分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

Flow是一个类型检查工具,相对TypeScript而言TypeScript是一门全新的语言,更加强大。那么我们为什么还要了解Flow?因为Flow在Vue\React等前端框架一些版本上都有使用,为方便对其中源码的研究,我认为还是有必须进行了解的。

Flow它比较简单,上手起来还是比较容易的,下面我们来快速上手一下。

一、项目初始化

  1. 创建一个空目录;
  2. 通过npm init --yes初始化项目(或yarn init --yes);
  • 注意:yarn是可以直接找到项目依赖cli程序,npm是需要指定目录才能找到。如果使用npm的话可以用npx去执行, 它跟yarn基本类似可以直接找到项目依赖cli程序。

二、安装Flow

通过npm安装flow到当前项目开发依赖。

npm install flow-bin --save-dev

三、使用Flow

在当前项目新建get-start.js文件,声明一个sum函数并指定传入参数和返回值的类型。

注意,要使用flow进行类型检查,文件开始必须要在注释中写上“@flow”。同时编辑器会报错是因为flow的语法不是js的标准语法,在这里我们使用flow去检查语法就应当把编辑器的语法检查关闭,以VScode为例在设置搜索javascript validate并把它禁用就可以了。

/**
 * get-start.js
 *
 * @flow
 */

function sum (a: number, b:number): number {
    return a + b
}
sum(1, '2')

npx flow init创建flow配置文件。

npx flow init

npx flow运行flow进行语法检查,此时我们可看到终端报错提示sum第二个b参数应传入数字的信息。

npx flow

四、使用官方模块编译

我们编写完带flow语法的js文件后是无法直接运行的(flow工具只是在编码阶段进行类型检查),原因也很简单因为flow语法并不是标准的js语法,需要编译进行类型注解的移除才能运行。

那么如何进行编译呢,最简单的方法就使用flow官方编译工具flow-remove-types。

安装flow-remove-types。

npm install flow-remove-types --save-dev

安装完成后,在终端运行npx flow-remove-types . -d dist(此处 “.”表示当前目录,-d后面填写要输出的目录)。运行过后就可以看dist目录及目录下编译过后的代码了,那么这些代码就可以直接在生产环境上运行了。

五、使用babel编译

安装@babel/core(babel的核心模块)、@babel/cli(babel的cli工具,可以让我们在终端使用命令行去执行编译)、@babel/preset-flow(preset-flow就是包括转换flow类型注解的插件)到当前项目开发依赖。

npm install @babel/core @babel/cli @babel/preset-flow --save-dev

安装完成后,在项目根目下创建babel的配置文件.babelrc并进行配置。

{
    "presets": ["@babel/preset-flow"]
}

配置完后在终端运行npx babel get-start.js -d dist,get-start.js是指定编译文件-d后面是输出目录。这里也可以指定一个目录,一般我们会将源码放到src目录下。

npx babel get-start.js -d dist

六、开发工具插件

到这里我们就可以使用flow进行开发了,但是在开发过程中我们每次对代码进行类型检查时都需要手动在终端中运行一下 npx flow 才能看到检查结果,这样的开发体验非常不好。

为提高开发体验这里我们通过安装一款插件进行解决。

以VScode为例,在扩展中搜索Flow Language Support插件进行下载安装。安装完成后就可以在编辑中及时看到代码出错的信息,要注意的是代码必须要保存后该插件才能进行检查。

其他编辑器也有对应的flow插件,具体请到flow官网进行查看。

七、Flow常见语法及类型

1、类型推断

在flow中某些情况下即使我们不使用类型注解,它也能自动为我们推断出数据的类型。比如以下代码中square方法传一个参数返回它的平方值,这里就只数字才能相乘,所以flow就推断出该参数应为数字类型,如果传入的不是数字代码就会报错。

尽管flow可以进行自动推断类型,但在一般情况还是建议大家使用类型注解,这样可提高代码的可读性、可靠性及可维护性。

/**
 * 类型推断
 *
 * @flow
 */
function square (n) {
    return n * n
}
// square('100')
square(100)

2、类型注解

直接在变量名后加上“ : <类型名称> ”来指定数据类型。函数参数同理,函数返回值类型在函数参数括号后加上“ : <类型名称> ”进行指定,void表示无返回值。

/**
 * 类型注解
 *
 * @flow
 */
let num: number = 100
function square (n: number): number {
    return n * n
}
function sayHi (mes: string): void {
    console.log(`Hello, ${mes}.`)
}

3、原始类型

Flow中字符串类型使用:string指定,数字类型使用:number指定,布尔类型使用:boolean指定,Null类型使用:null指定,undefined类型使用:void指定,Symbol类型使用:symbol指定。

/**
 * 原始类型
 *
 * @flow
 */
const str: string = 'foobar'
const num: number = Infinity // NaN // 100
const bool: boolean = false // true
const n: null = null
const u: void = undefined
const s: symbol = Symbol()

4、数组类型

Flow中数组类型指定可以使用:Array<类型名称>,也可以使用:类型名称[]。给数组元素指定不同类型使用:[string, number],这里也可叫作元组。

/**
 * 数组类型
 *
 * @flow
 */
const arr1: Array<number> = [1, 2, 3]
const arr2: number[] = [1, 2, 3]
// 元组
const foo: [string, number] = ['foo', 100]

5、对象类型

Flow中对象类型指定使用:{成员名称: 类型名称}指定,可选成员在后面加个问号。指定通用成员类型使用:{[类型名称]: 类型名称}。

/**
 * 对象类型
 *
 * @flow
 */
// obj1的值必须为{ foo: 字符串, bar: 数字 }
const obj1: { foo: string, bar: number } = { foo: 'string', bar: 100 }
// obj2的值foo为可选
const obj2: { foo?: string, bar: number } = { bar: 100 }
// obj3的值键和值都是字符串就可以
const obj3: { [string]: string } = {}
obj3.key1 = 'value1'
obj3.key2 = 'value2'

6、函数类型

Flow中函数类型的定义为: (参数类型, 参数类型...) => 返回值类型。

/**
 * 函数类型
 *
 * @flow
 */
function foo (callback: (string, number) => void) {
    callback('okay', 200)
}
foo(function(str, num) {
    console.log(str, num) // okay 200
})

7、特殊类型

字面量类型

字面量类型就是值必须是字面量类型中的一个,不能是其他值。

/**
 * 特殊类型
 * 字面量类型
 * @flow
 */
const a: 'foo' = 'foo'
// 使用 | 表示该变量可以是 类型1 或 类型2...
const type: 'success' | 'fail' | 'warning' = 'success'

声明类型

使用type关键字定义声明类型,可以自定义自己想要的类型。

/**
 * 特殊类型
 * 声明类型
 * @flow
 */
type StringOrNumber = string | number
const b: StringOrNumber = 'string'
const c: StringOrNumber = 100

Maybe类型

就是可能是这个类型,也可能是null或undefined,在类型名称前加问号定义。

/**
 * 特殊类型
 * Maybe类型
 * @flow
 */
const gender: ?number = undefined
// 相当于
const gender: number | null | void = undefined

Mixed类型和Any类型

Mixed和Any类型可以接收任意类型的值,可以理解成所有类型的联合类型。区别在于Any是弱类型的,在语法上不会报错。一般情况下建议使用Mixed类型,any类型只是为了兼容以前的旧版本。

/**
 * 特殊类型
 * Mixed类型
 * @flow
 */
// string | number | boolean | ....
function passMixed (value: mixed) {
  if (typeof value === 'string') {
    value.substr(1)
  }
  if (typeof value === 'number') {
    value * value
  }
}
passMixed('string')
passMixed(100)

function passAny (value: any) {
  value.substr(1)
  value * value
}
passAny('string')
passAny(100)

8、运行环境api

运行环境api指的是js在不同平台运行时使用的api,它也有对应的类型,比如获取一个id为app的元素那么它的类型就是HTMLELement或null。这些类型的声明文件在flow安装时都已经自动下载下来了。

/**
 * 运行环境 API
 *
 * @flow
 */
const element: HTMLElement | null = document.getElementById('app')

以上并不是Flow的全部内容,只是一些基础的介绍。去深入了解Flow的所有内容个人认为没有必要,学习这些东西只是为了在看一些源码的时候能够看得懂,比如Vue2就使用了Flow。

当然想要了解更多也可以到Flow官网或其他网站进行了解。

flow.org www.saltycrane.com/

-EOF-