JavaScript 是一门弱类型且动态类型的语言,数据类型没有约束,有时候会引发一些问题。可以借助 Flow 这样一款静态类型检测工具来弥补 JavaScript 类型系统的缺陷。

上手

Flow 是一个 npm 模块。安装后需要初始化配置。

  1. npm i flow-bin -D
  2. npx flow --init

在 js 文件开头写上 @flow 的注释, Flow 就能识别到这个文件需要检测。

  1. // @flow
  2. function sum (a: number, b: number) {
  3. return a + b
  4. }
  5. sum(100, 100)
  6. sum('100', '100') // 报错
  1. 如果检测没有问题,那么需要移除掉类型注解,因为原生 JavaScript 并不支持。可以用官方的 flow-remove-types 模块或者用 Babel + @babel/preset-flow
  1. npm i flow-remove-types @babel/cli @babel/core @babel/preset-flow -D
  1. 如果使用 Babel,需要添加配置文件 .babelrc
  1. {
  2. "presets": ["@babel/preset-flow"]
  3. }

使用方法:

  1. npx flow-remove-types 目标文件夹 -d 输出文件夹
  2. npx babel 目标文件夹 -d 输出文件夹

使用 Flow 官方提供的 vs code 插件,可以更直观地在编译器看到类型错误的提示,不用每次都输入命令。

类型推断

Flow 会根据代码自动推断参数应该是什么数据类型。

  1. /**
  2. * 类型推断
  3. *
  4. * @flow
  5. */
  6. function square (n) {
  7. return n * n
  8. }
  9. // square('100') 因为 square 里面对传入的参数使用了乘法,所以 Flow 会自动推断传入参数应该是数字
  10. square(100)

类型注解

  1. /**
  2. * 类型注解
  3. *
  4. * @flow
  5. */
  6. function square (n: number) {
  7. return n * n
  8. }
  9. let num: number = 100
  10. // num = 'string' // error
  11. function foo (): number {
  12. return 100 // ok
  13. // return 'string' // error
  14. }
  15. function bar (): void {
  16. // return undefined
  17. }

数据类型

原始数据类型

  1. /**
  2. * 原始类型
  3. *
  4. * @flow
  5. */
  6. const a: string = 'foobar'
  7. const b: number = Infinity // NaN // 100
  8. const c: boolean = false // true
  9. const d: null = null
  10. const e: void = undefined
  11. const f: symbol = Symbol()

数组

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

对象

  1. /**
  2. * 对象类型
  3. *
  4. * @flow
  5. */
  6. const obj1: { foo: string, bar: number } = { foo: 'string', bar: 100 }
  7. const obj2: { foo?: string, bar: number } = { bar: 100 }
  8. const obj3: { [string]: string } = {}
  9. obj3.key1 = 'value1'
  10. obj3.key2 = 'value2'

函数

  1. /**
  2. * 函数类型
  3. *
  4. * @flow
  5. */
  6. function foo (callback: (string: string, number: number) => void) {
  7. callback('string', 100)
  8. }
  9. foo(function (str, n) {
  10. // str => string
  11. // n => number
  12. })

特殊类型

  1. /**
  2. * 特殊类型
  3. *
  4. * @flow
  5. */
  6. // 字面量类型
  7. const a: 'foo' = 'foo' // 只能是 foo
  8. const type: 'success' | 'warning' | 'danger' = 'success' // 只能是其中一个
  9. // ------------------------
  10. // 声明类型
  11. type StringOrNumber = string | number
  12. const b: StringOrNumber = 'string' // 100
  13. // ------------------------
  14. // Maybe 类型
  15. const gender: ?number = undefined
  16. // 相当于
  17. // const gender: number | null | void = undefined

Mixed 和 Any

Mixed 和 Any 表示任意类型,区别在于 Mixed 是强类型的,Any 是弱类型的。如果调用一些专属的类型方法,Mixed 需要先明确是这种类型。

  1. /**
  2. * Mixed Any
  3. *
  4. * @flow
  5. */
  6. // string | number | boolean | ....
  7. function passMixed (value: mixed) {
  8. if (typeof value === 'string') {
  9. value.substr(1)
  10. }
  11. if (typeof value === 'number') {
  12. value * value
  13. }
  14. }
  15. passMixed('string')
  16. passMixed(100)
  17. // ---------------------------------
  18. function passAny (value: any) {
  19. value.substr(1)
  20. value * value
  21. }
  22. passAny('string')
  23. passAny(100)