amfe / article

7.58k stars 1.07k forks source link

flow——A static type checker for javascript #32

Open qingying opened 8 years ago

qingying commented 8 years ago

介绍

众所周知,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

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

myheartwillgoon commented 8 years ago

1+2不应该为13吧

soulmachine commented 8 years ago

有没有研究过怎么跟 webpack 集成呢?我搜索了一下,貌似大部分项目还是单独运行 flow check 命令来检查。目前找到的最方便的一个方法是使用这个 babel plugin babel-plugin-typecheck

dd1994 commented 8 years ago

@soulmachine webpack 不是做这类事情的,它只是打包用的。运行任务的话就用 make 或者 gulp 之类的东西。

xiaoqi1102 commented 8 years ago

@soulmachine @dd1994 webpack 确实有一个 flowcheck-loader 可以用的 https://www.npmjs.com/package/flowcheck-loader

dd1994 commented 8 years ago

@xiaoqi1102 我只能说这个插件非常不科学,做了不应该做的事,所以 star 数这么少 :new_moon_with_face:

skyblue commented 8 years ago

我觉得在构建前跑flow挺合理的啊,类似eslint