Flow概述--JavaScript的类型检查器

58 阅读8分钟

blog.csdn.net/liuliuliuli… 首选项=>设置 =>javascript validate=

Flow概述

背景:2014年由facebook推出的JavaScript类型检查工具,可以避免JavaScript弱类型语言所带来的的弊端,vue和react中都有适应 工作原理:在JavaScript代码中通过添加一些类型注解的方式来标记代码中每个变量和参数的类型,然后flow再根据这些类型注解就可以检查代码中是否存在类型使用上的异常,从而实现在开发阶段对类型异常的检查,这就避免了再到运行阶段去发现这种类型使用上的错误

Flow只是一个小工具,而TypeScript是一门全新的语言

Flow快速上手

背景:flow是以一个npm模块的形式来工作的,所以需要首先初始化一个package.json文件去管理项目的依赖,然后 npm i flow-bin -D 可以在命令行中使用flow命令

使用类型注解的前提:在当前文件(js)最开始的位置通过注释的方式添加一个@flow的标记 // @flow flow去执行检测时才会检查这个文件 注意点 @flow之间一定不能有空格

// @flow
function (a: number, b: number) {
   return a + b
}
// 发现number出报错提示,这是因为:number并不是标准的js语法,而vscode会自动校验js语法,因为我们现在使用了flow,所以不再需要vscode自带的js语法校验

类型注解报错解决办法

1:关闭vscode的js语法校验 首选项=>设置=>输入javaScript:Validate=>去掉勾选 2:命令行执行 npm flow 命令报错 Could not find a .flowconfig in . or any of its parent directories.(找不到一个flowconfig的文件)这个文件是flow的一个配置文件,我们可以通过npm flow init 没有全局安装flow命令的话)命令去初始化这个文件,执行命令后发现在根目录多了一个.flowconfig文件 3:在根目录下输入 npm flow 命令,会类型检查根目录下所有带有// @flow标记 的文件,并将类型错误在命令行中展现出来 npm flow 开启一个flow服务器,监视文件的变化 npm flow stop 关闭这flow服务

Flow编译移除注解

  • 在正常那个的js运行环境中,是不能正常运行带有类型注解的js代码(因为这不是正确的js语法),比如 node index.js 会报错(js文件中有flow的类型注解)
  • flow的类型注解只是帮助我们在代码编译阶段帮助我们找出问题的,而在实际的运行环境中,它没有任何的必要,所以我们需要使用工具在完成编码后自动移除掉我们之前添加的类型注解(flow-remove-types 模块) 步骤: 1:安装 flow-remove-types 模块 npm i flow-remove-types -D 2:npm flow-remove-types 源代码所在的目录(src) -d 转换之后的输出目录 npm flow-remove-types ./ -d dist 在根目录下多一个dist目录(会将src整个目录下的文件复制带dist目录下.只不过是将src下带有// @flow标记的文件移除了类型注解)

Flow开发工具插件 Flow Language Support

  • 之前通过npm flow命令执行的检查出来的类型错误都输输出到命令行(控制台)上,而我们需要每次需要打开终端,输入相应的命令,才会看到类型错误的原因,这种方式不是很直观
  • Flow Language Support开发工具=>直接在开发工具(vscode)中显示出来类型错误 小提示:因为Flow Language Support不是vscode自带的检查工具,所以检查时必须要保存(ctrl+s)后,稍微延迟才会检查类型错误

类型判断

flow除了通过类型注解的方式去标记代码中每个成员的类型,flow还可以很聪明的自动帮助我们推断代码中每个成员的类型

// @flow
function fn(n) {
    return n * n
}
// 正常情况测下参数n必须是一个数字,但我们不添加类型注解的情况下,系统会自动推断我们参数的类型
fn("123") //类型报错

但为了代码便于阅读:我们还是最好每个成员都加上类型注解

类型注解

类型注解的方式 变量的注解 变量: 类型名称 const a: number = 1 函数返回值的注解 函数参数的括号后面: 类型名称 // 函数有返回值的情况 function foo(): number {

} // 函数没有返回值的情况:实际上返回的是undefined,返回值的类型名称是void function foo(): void {

}

原始类型

string number boolean null undefined syn=mbol

在flow中undefined比较特殊,如果变量或者函数返回值是undefined,那么它的类型名称是void

// @flow
const a: string = "123"
const b: number = 123
const c: boolean = true
const d: null = null
const e: void = undefined
const f: symbol = Symbol()

数组类型

flow中支持两种数组类型的表示方法
// @flow
// Array类型,这个类型需要一个泛型参数来表示数组中每个元素的类型,泛型这个概念会在后面的TypeScript中去详细介绍
const arr1: Array < number >= [1, 2]
// 元素类型后面跟上一个方括号,也可以表示元素是全部数字组成的数组
const arr2: number[] = [1, 2]

//补充: 如果需要表示一个固定长度的数组,我们可以使用一种类似数组字面量的形式来表示==>元组
const arr3: [number, string] = [1, "2"]

对象类型

// @flow
// 对象类型
// 在flow中描述对象类型的方式和对象字面量的语法非常类似
// 在对象中必须要有foo和bar两个成员,且它们的类型是字符串和数字
const obj1: {
    foo: string,
    bar: number
} = {
    foo: "12",
    bar: 12
}

// 如果对象的某个成员是可选的,在成员后面加上问号,代表这个成员可有可无
const obj2: {
    foo ? : string,
    bar: number
} = {
    bar: 12
}


// 任意那类型的键,任意类型的值,普通对象的键可以是字符串和symbol,值可以是任意类型
const obj3: {
    [string]: string
} = {
    bar: "12"
}

const obj4: {
    [string | symbol]: string
} = {
    bar: "12"
}

函数类型

// @flow
// 对于函数类型的限制,一般是对函数的参数类型和返回值类型进行约束
// 参数限制=>参数后面添加类型注解
// 返回值限制=>在函数()后面添加类型注解
function foo(a: number, b: string): void {
    console.log(a, b)
    // 不能有return具体数值(除非return undefined)
    return undefined
}
foo(1, " 2")

1:除此之外函数在js中也是一种特殊的数据类型,很多时候会把函数放到变量当中,例如我们传递回调函数参数的时候,就会把一个函数放到一个回调参数的变量中 2:我们想限制这个回调函数的参数和它的返回值,我们可以使用一种类似箭头函数的函数签名来限制

// @flow
function foo(callback: (string, number) => void) {
    // 回调函数的第一个参数必须是字符串,第二个参数必须是数字,并且这个回调函数没有返回值
    callback("string", 100)
}
foo(function (str, n) {})

特殊类型

  • 字面量类型 与传统类型不同的是:字面量类型限制我们我们的变量必须是一个值
// @flow

// 字面量类型
const a: "foo" = "foo"
// 此时a变量中只能存放"foo"这个字符串,如果是其它任何值,都会类型报错
const type: "success"|"waring"|"danger"="success"
  • 联合类型(也称或类型) 字面量类型很少单独使用,而是配合联合类型的用法去组合几个特定类型的值
// @flow
// 联合类型
// type变量的值只可能是 "success"|"waring"|"danger"之一,否则会类型报错
const type: "success" | "waring" | "danger" = "success"
  • 联合类型不仅可以和字面量类型组合使用,还可以用在普通类型上
// @flow

// 联合类型和普通类型组使用
const b: string | number = "123"
// 变量b可以是字符串类型或者数字类型

还可以使用type关键字来单独声明一个类型,用来表示多个多个类型联合之后的结果(用type单独声明一个类型)

// @flow
// type关键字申明一个联合类型的结果,相当于一个类型的别名,我们可以在多个地方重复使用它
type stringOrNumber = string | number
const b: stringOrNumber = "123"

Mixed与Any类型

// @flow 
//mixed类型--任意类型,可以理解为所有类型的联合类型
function passMixed(value: mixed) {
    //编译阶段,在没有确定参数类型的情况下,不能调用具体类型的方法,否则会报错
    value.substr(1) // 报错
}
// 当我们调用passMixed函数时,参数可以为任意类型
passMixed(12)
passMixed("123")

// any类型--任意类型
function passAny(value: any) {
    // 在函数内部可以调用value的substr方法,只有在运行阶段,发现函数调用传进来的参数是非字符串才会报错
    value * substr(1)
}
// 当我们调用passAny函数时,参数可以为任意类型
passAny(12)
passAny("123")

// any是弱类型,mixed是强类型

mixed类型改进

// @flow 
// 为了明确value这个变量的类型,我们可以通过typeof来实现(类型判断)
function passMixed(value: mixed) {
    if (typeof value === 'string') {
        value.substr(1)
    }
    if (typeof value === 'string') {
        value * value
    }

}
passMixed(12)
passMixed("123")

小结:在开发过程中尽量使用mixed类型

运行环境的API 内置对象

// @flow // JavaScript不是独立工作的,而是必须要运行在某一个特定运行环境当中,例如浏览器环境或者时node环境.这些环境一定会提供一些API给我们使用,例如浏览器中dom和bom,在node当中有各种模块,对于这些API对象同样有一些类型限制 const element: HTMLElement = document.getElementById("app") // 当参数不是字符串则类型报错