Flow(JavaScript的静态类型检查器)
Flow可以弥补JavaScript带来的一些弊端,为JavaScript提供了更完善的类型系统
Flow工作原理:在代码当中通过添加一些类型注解的方式,来去标记我们代码当中每个参数,每个变量,它是什么类型的,然后Flow可以根据这些类型注解就可以检查代码当中是否会存在类型使用的异常,从而去实现我们在开发阶段对类型异常的一个检查,这就避免了我们在运行阶段去发现类型的错误
- 类型注解 ":类型"的结构
- 特点1:代码当中的类型注解可以通过Babel或Flow官方提供的模块自动去剔除,所以在生产环境当中这些注解不会有任何的影响
- 特点2:Flow并不需要给每个变量都添加注解,可以根据需要在需要的地方添加类型注解,不需要可以不添加
Flow快速上手
- 因为Flow是以一个npm模块化的形式去工作的,我们需要初始化package.json用于管理我们的项目依赖
yarn init -yes
- 安装Flow,作为项目依赖安装,更加方便管理,安装成功后可以在node_modules/bin中找到flow的可执行文件,那么我们可以在命令行当中执行flow,用于检测项目当中对应的代码中的类型异常
yarn add flow-bin --dev
- 使用类型注解的前提是在当前js文件的上方添加注释标记@flow,这样flow在执行检测时才会检查这个文件
//@Flow
function sum(a:number,b:number){
return a + b
}
sum(10,10)
sum('10','10')
- 在命令行创建flow初始化文件
yarn flow init
生产.flowconfig文件
5. 运行flow,进行类型检查
yarn flow
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kQSr8W72-1597675596731)(F5BC41ED6B5F450D9AA32A891BFEA453)]
- 在flow完成过后可以在命令行使用命令结束这个服务
yarn flow stop
小知识:在vscode–file–preference–setting搜索javascript validate勾掉对勾可以关闭js的语法检查
编译 (通过编译移除类型注解)
类型注解并不是js的标准语法,当添加类型注解过后,代码是没有办法正常运行的,例如
//@flow
function sum(a:number,b:number){
return a + b;
}
sum(100,100)
sum('100','100')
执行命令
node flow_dome01.js
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XTTbJeex-1597675596733)(5A5F1A47FCB24CBEA701E62AF8CEB437)]
解决这种问题可以移除类型注解,因为类型注解实际上使我们在编码环节使用的,在运行中实际上是没有必要的,
移除类型注解的两种解决方案
1.使用flow官方提供的flow-remove-types模块,这也是 最快速最简单的方案
//命令行安装依赖
yarn add flow-remove-types --dev
运行flow-remove-types,生成变编译后的文件
//yarn flow-remove-types [输入文件路径] -d [输出的文件路径]
//-d是转换的意思
yarn flow-remove-types . -d dist
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-st8ONInu-1597675596733)(A8A8DF1F275E458C97FFC150C26E1E18)]
这样就没有类型注解了
// dist/flow_dome01.js
function sum(a ,b ){
return a + b;
}
sum(100,100)
sum('100','100')
把所有的文件都放置src文件夹能够避免误删第三方的文件
//yarn flow-remove-types [输入文件路径] -d [输出的文件路径]
//-d是转换的意思
yarn flow-remove-types src -d dist
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vXFTaPn0-1597675596734)(CDD25A0CC527473EA74D42ABD3410ACC)]
flow方案是如何解决js的弊端的?把编写的代码和实际运行的代码分开,中间加入了编译的环节,这样我们就可以使用一些扩张语法,使得类型检测变得可能
2.babel插件自动移除代码当中的类型注解
安装babel插件
- 安装 babel的核心模块
- babel的cli工具,能够让我们使用babel命令去完成编译
- 安装babel的preset-flow 包含了我们转换flow类型注解的插件
yarn add @babel/core @babel/cli @babel/preset-flow --dev
配置.babelrc文件
{
"presets":["@babel/preset-flow"]
}
运行babel编译命令
yarn babel src -d dist
package.json
{
"name": "dome20200524",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"devDependencies": {
"@babel/cli": "^7.8.4",
"@babel/core": "^7.9.6",
"@babel/preset-flow": "^7.9.0",
"flow-bin": "^0.125.1",
"flow-remove-types": "^2.125.1"
}
}
flow开发工具插件
在vscode搜索插件flow看到Flow Language Support下载,能够让我们在保存代码后直观的看到类型检查的报错
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BI2JGzH3-1597675596735)(69F0B83654F244769973EF2A25707E6E)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pQh1Evj2-1597675596735)(B35AF837E18B469C82B0FA5071122F07)]
类型推断 type inference
flow能够根据代码的实际情况自动推断出数据类型
/**
* 类型推断
* @flow
*/
function cf(n,m){
return n*m
}
cf('100','100')
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KwLhsrVy-1597675596736)(33930F61852040BA80A1A5A17756DB7D)]
我们更加建议为代码的每一个成员添加注解,这样会有更好的可读性
flow 类型注解 Type Annotations
flow可以帮我们推断出绝大多数的变量或类型,类型注解可以用了函数的参数,变量的类型以及函数返回的类型
/**
* 类型注解
* @flow
*/
function cf(n,m){
return n*m
}
cf('100','100')
let num:number = 123;
// num = 'sss';//会报错
function next():number {
// return 100;
return 'cc';//报出语法错误
}
//需要注意的是如果没有返回值,默认返回undefined,也会 报错
function pre(): void{
没有返回值就标记void
}
原始类型
支持6种原始类型数据
/**
* 原始数据类型
* @flow
*/
const a:string = 'string'
const b:number = Infinity//NaN//100
const c:boolean = true //false
const d:null = null
const e:void = undefined
const f:symbol = Symbol()
数组类型
有结构的类型限制
/**
* 数组类型
* @flow
*/
// 定义纯数据类型的数组
const arr:Array<number> = [1,2,3]
const arr2:number[] = [4,5,6]
// 元组,定义固定长度的数组
const arr3:[Number,string] = [10,'hh']
当一个函数当中同时返回多个返回值的时候可以使用元组类型
对象类型
/**
* 对象类型
* @flow
*/
//限制变量是对象类型使用{}
// 设置固定的键和值的类型,对象就必须有这些成员
const obj1 : {boo:string,coo:number} = {boo:'cc',coo:123}
// ?表示这个成员可有可无
const obj2 :{boo?:string,coo:number} = {coo:123}
// 设置任意成员的键值对类型,设置成什么类型就必须是什么类型
const obj3:{[string]:string} = {}
// obj3.key1 = 123;//Cannot assign `123` to `obj3.key1` because number [1] is incompatible with string [2].
obj3.key1 = 'abc'
obj3.key2 = 'def'
函数类型
限制回调函数的参数和返回值,可以使用类似箭头函数的函数签名的限制
/**
* 函数类型
* @flow
*/
function foo(callback: (string,number)=>void){
callback('str',100)
}
foo(function(str,num){
// str==>string
// num==>number
})
特殊类型
/**
* 特殊类型
* @flow
*/
//字面量类型:限制变量必须是某一个值,一般不会单独使用,会配合联合用法组合使用这个值
const a :'foo' = 'foo'
// 联合类型用法:又称或类型,值只能存放三种变量之一
const b: 'success' | 'warning' | 'danger' = 'success'
//也可以用联合类型定义变量的类型
const c: string | number = 100//'100'
//用type关键词给类型别名或者是单独生成一个类型
type stringOrNumber = string | number
const d:stringOrNumber = '122'
//maybe类型 有可能类型,用?表示
const e: ?number = undefined//null//100
flow Mixed和Any(任意类型)
Mixed类型是所有类型的联合类型,可以是任何一个值
/**
* Mixed和Any类型
* @flow
*/
function passMixed(pass:mixed){
}
passMixed('ss')
passMixed(123)
passMixed(true)
function passAny(pass:any){
}
passAny('aa')
passAny(123)
passAny(null)
在语法上any是弱类型,mixed是强类型,any主要是为了兼容老代码产生的
/**
* Mixed和Any类型
* @flow
*/
function passMixed(pass:mixed){
if(typeof pass === 'string'){
pass.substr(1)
}
if(typeof pass === 'number'){
pass*pass
}
}
passMixed('ss')
passMixed(123)
passMixed(true)
function passAny(pass:any){
pass.substr(1)
pass*pass
}
passAny('aa')
passAny(123)
passAny(null)
flow小结
flow官方类型文档
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-KWlII3KJ-1597675596737)(88A3A7D8A7EF4194918F06740C5B4869)]
第三方类型手册
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RV3zsF9S-1597675596737)(350746BEE9E14B8A93697CD4B18F4951)]
flow运行环境api的支持
/**
* 运行环境api
* @flow
*/
const obj:HTMLElement | null = document.getElementById('div')
api对应声明文件的链接
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Z16hRbPx-1597675596738)(D045D2F7AC39491BAA24F43AB406441B)]