Skip to content

flow——A static type checker for javascript #32

Open
@qingying

Description

@qingying

介绍

众所周知,javascript是一个动态类型语言,变量类型不需要声明,运算过程中会根据需要自动转换类型,这个是js的优点,够灵活,编码简单。但是同时也是软肋,相信很多人都会遇到这个问题,明明1+2我希望得到3,但是很多时候得到的却是13,什么时候number转成了string都不知道。相比一步一步查出哪里转的,这样写parseInt(1)+parseInt(2)或许更省力更有保障。
今天给大家介绍的flow则可以避免以上的问题。flow 是facebook团队出的一个js静态类型检测器,目的是通过最小的代码修改检测出代码中的类型问题。

安装

官网提供了众多安装方法,起初我觉得使用npm应该会是最便捷的。

     npm install flow-bin —global

真的很慢,请耐心等待。
很慢之后还不一定会成功。
最后我这边实验出比较简单的方法,首先下载文件,然后在终端执行$PATH,找出环境变量路径,把下载的flow文件复制过去就行。

使用

在项目目录下执行 flow init,会生成一个.flowconfig文件
在需要检测的文件顶部增加注释

/* @flow */

执行flow check,检测你代码中是否有类型错误。
示例:

function simple(string){
    return string.length;
}
simple(1);

示例中,想取传入参数的length属性,flow检测到传入值是一个number,不存在length,则会报错。如图
img

flow server

flow server是为了提高检测效率的后台程序,支持在后台运行,并且只监测有修改的文件。
flow:项目第一次执行或者.flowconfig有修改第一次执行的时候会比较慢,请耐心等下
flow:后面有修改之后执行能快速显示错误
flow stop:项目开发完成停止服务

flowconfig

  • [ignore]忽略的文件,路径的匹配规则是正则表达式
  • [include]需要检测的其他目录的文件
  • [libs]当文件中有第三方库引用或者require全局的module时,需要在一个单独的文件里declare这个对象,这个的值是所有declare路径的集合
  • [options]包含若干key-value的配置,详情见官方文档

libs示例

var React = require('react');
var com = React.create({
    render: function(){
        return (
            <div className="page"></div>
        )
    }
})

示例中引用了react模块,没有带相对路径,flow找不到引用的地方。直接执行flow会报错,如图
img
这个时候需要我们在libs对应的目录下增加一个declare的文件,用了告诉flow我们这个引用的对象有哪些方法和熟悉

declare module react {
    declare function create(): any;
}

变量赋值类型

除了通过变量的属性和方法来推断变量类型是否正确外,flow还支持通过在代码里增加类型声明,来达到更精准的错误提示。变量声明类型示例如下

class People {
    name: string;
    constructor(name:string){
        this.name = name
    }
    getAge():number{
        return 18;
    }
}

function getLength(param?:string):number {
    /*param?:string传参类型什么,?表示此处可不传值;*/
    /*\:number为函数返回值类型,如果没有return可不写或写void*/
    var s:string = 'string';/*字符*/
    var ss:String = new String('string');/*字符对象*/

    /* s = ss*///类型不同,flow会报错

    var n:number = 12;/*数字*/
    var nn:Number = new Number(12);/*数字对象*/

    var b:boolean = true;/*bool值,仅能为true/false*/
    var bb:Boolean = new Boolean(true);/*bool值对象*/

    var o:{prop1:number,prop2:string} = {
        /*对象熟悉声明*/
        prop1: 12,
        prop2: '21123'
    }

    var v:void = undefined;/*undefined*/
    var a:any = 'aa';/*任意类型,除undefined*/
    var m:mixed = '1';/*任意类型+undefined*/
    var mm:mixed = undefined;/*任意类型+undefined*/

    var aa:Array<number> = [1,2,3,4];/*数组内值类型声明*/

    var P:Class<People> = People;/*自定义类型声明*/
    var p:People = new People('pt');/*自定义People类型*/

    if (param) {
        return param.length;
    } else {
        return 0;
    }
}

flow的两种模式

/@flow/ 只要带有这个注释,都会进行类型检测
/@flow weak/ 只对有加类型声明的变量进行类型检测

代码编译

增加类型声明的flow语法不是js的标准语法,这里需要使用babel来进行转换。目前可以选择使用的是babel的preset为react,或者babel的plugins为transform-flow-strip-types。不过在使用过程中发现class语法里react和flow同时解析会出现错误,所以为了保险起见最好先执行flow语法转换再做其他的语法转换。示例如下:

gulp.task('babel',['clean',],function(cb){
  return gulp.src('src/*.js')
         .pipe(
            babel({
              plugins: ["transform-flow-strip-types"]
            })
          )
         .pipe(babel({
            presets: ['react','es2015']
         }))
         .pipe(gulp.dest('build/'));
})

更多第一手资料,参见flow的官方文档
本文中提到的代码示例https://github.com/qingying/flow-demo

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions