JavaScript 是一门弱类型且动态类型的语言,数据类型没有约束,有时候会引发一些问题。可以借助 Flow 这样一款静态类型检测工具来弥补 JavaScript 类型系统的缺陷。
上手
Flow 是一个 npm 模块。安装后需要初始化配置。
npm i flow-bin -D
npx flow --init
在 js 文件开头写上 @flow 的注释, Flow 就能识别到这个文件需要检测。
// @flow
function sum (a: number, b: number) {
return a + b
}
sum(100, 100)
sum('100', '100') // 报错
如果检测没有问题,那么需要移除掉类型注解,因为原生 JavaScript 并不支持。可以用官方的 flow-remove-types 模块或者用 Babel + @babel/preset-flow。
npm i flow-remove-types @babel/cli @babel/core @babel/preset-flow -D
如果使用 Babel,需要添加配置文件 .babelrc:
{
"presets": ["@babel/preset-flow"]
}
使用方法:
npx flow-remove-types 目标文件夹 -d 输出文件夹
npx babel 目标文件夹 -d 输出文件夹
使用 Flow 官方提供的 vs code 插件,可以更直观地在编译器看到类型错误的提示,不用每次都输入命令。
类型推断
Flow 会根据代码自动推断参数应该是什么数据类型。
/**
* 类型推断
*
* @flow
*/
function square (n) {
return n * n
}
// square('100') 因为 square 里面对传入的参数使用了乘法,所以 Flow 会自动推断传入参数应该是数字
square(100)
类型注解
/**
* 类型注解
*
* @flow
*/
function square (n: number) {
return n * n
}
let num: number = 100
// num = 'string' // error
function foo (): number {
return 100 // ok
// return 'string' // error
}
function bar (): void {
// return undefined
}
数据类型
原始数据类型
/**
* 原始类型
*
* @flow
*/
const a: string = 'foobar'
const b: number = Infinity // NaN // 100
const c: boolean = false // true
const d: null = null
const e: void = undefined
const f: symbol = Symbol()
数组
/**
* 数组类型
*
* @flow
*/
const arr1: Array<number> = [1, 2, 3]
const arr2: number[] = [1, 2, 3]
// 元组
const foo: [string, number] = ['foo', 100]
对象
/**
* 对象类型
*
* @flow
*/
const obj1: { foo: string, bar: number } = { foo: 'string', bar: 100 }
const obj2: { foo?: string, bar: number } = { bar: 100 }
const obj3: { [string]: string } = {}
obj3.key1 = 'value1'
obj3.key2 = 'value2'
函数
/**
* 函数类型
*
* @flow
*/
function foo (callback: (string: string, number: number) => void) {
callback('string', 100)
}
foo(function (str, n) {
// str => string
// n => number
})
特殊类型
/**
* 特殊类型
*
* @flow
*/
// 字面量类型
const a: 'foo' = 'foo' // 只能是 foo
const type: 'success' | 'warning' | 'danger' = 'success' // 只能是其中一个
// ------------------------
// 声明类型
type StringOrNumber = string | number
const b: StringOrNumber = 'string' // 100
// ------------------------
// Maybe 类型
const gender: ?number = undefined
// 相当于
// const gender: number | null | void = undefined
Mixed 和 Any
Mixed 和 Any 表示任意类型,区别在于 Mixed 是强类型的,Any 是弱类型的。如果调用一些专属的类型方法,Mixed 需要先明确是这种类型。
/**
* Mixed Any
*
* @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)