Flow 文档记录

作者: weqwqwqwe121312 | 来源:发表于2018-09-06 16:47 被阅读13次

    持续更新中

    Flow介绍

    Flow是一个作用于JavaScript语言的静态类型检查程序。

    示例:

    // @flow
    function square(n: number): number {
        return n * n;
    }
    square("2"); // Error!
    

    Flow可以很好的理解JavaScript语言。上述例子中我们只需要使用少量的类型描述,Flow就可以准确检测类型错误。很多时候,Flow可以理解我们的代码可以不需要任何类型描述。如下代码所示:

    // @flow
    function square(n) {
        return n * n;
    }
    square("2"); // Error!
    

    Primitive Type (原始类型)

    • Booleans
    • Strings
    • Numbers
    • null
    • undefined (在Flow中类型使用void代替)
    • Symbols (Flow不支持)

    原始类型在flow中有两种存在形式:

    1、以值的形式出现,此时类型需要小写,如:

    // @flow
    function method (x: number, y: string){
        // ...
    }
    method(3.2, 'hello')
    

    2、以包装对象的形式出现(JS中基础包装对象有三种,分别是Number,String和Boolean),此时类型需要首字母大写,类似构造函数,如:

    // @flow
    function method (x: Number, y: String){
        // ...
    }
    method(new Number(42), new String('hello'))
    

    值得注意的是:

    • JS可以对类型进行隐式转换,在使用Flow时,需要显示转换。
    • boolean和Boolean是两种不同的类型。boolean类型的值应该是truefalse或者是一个类似a === b的表达式;Boolean类型的值应该是new Boolean(x),使用new和构造函数创建出来的值。
    • number和Number是两种不同的类型。number类型的值应该是33.14或者是一个类似parseFloat(x)的表达式;Number类型的值应该是new Number(x),使用new和构造函数创建出来的值。
    • JS允许字符串拼接其他类型的值,Flow只支持字符串拼接字符串或者数字
    • string和String是两种不同的类型。string类型的值应该是"foo""foo" + 42或者是一个类似parseFloat(x)的表达式;String类型的值应该是new String(x),使用new和构造函数创建出来的值。
    • void类型表示undefined,undefined与null是两个不同的类型。

    不确定类型

    在类型是可选的时,可以为类型添加一个标记,如:?string

    可选的对象属性

    对象类型支持设置可选属性,如{propertyNmae?: string},这些可选属性除了自身设置的类型,也支持void类型以及完全忽略该字段,但是不支持null

    // @flow
    function acceptsObject(value: {foo? string}) {
        // ...
    }
    acceptsObject({foo: 'bar'}) // Works!
    acceptsObject({foo: undefined}) // Works!
    acceptsObject({foo: null}) // Error!
    acceptsObject({}) // Works!
    

    可选的函数属性

    在属性名后增加标记,表示该属性为可选项。可选属性除了自身设置的类型,也支持void类型以及完全忽略该字段,但是不支持null

    // @flow
    function acceptsString(value?: string) {
        // ...
    }
    acceptsObject('bar') // Works!
    acceptsObject(undefined) // Works!
    acceptsObject(null) // Error!
    acceptsObject() // Works!
    

    有默认值的函数属性

    在属性的类型后增加默认值。这些属性除了自身设置的类型,也支持void类型以及完全忽略该字段,但是不支持null

    // @flow
    function acceptsString(value: string = 'foo') {
        // ...
    }
    acceptsObject('bar') // Works!
    acceptsObject(undefined) // Works!
    acceptsObject(null) // Error!
    acceptsObject() // Works!
    

    Literal Type (值类型)

    Flow也支持使用具体的值作为类型。
    如下示例,使用数字2作为类型:

    // @flow
    function acceptsTwo(value: 2) {
        // ...
    }
    acceptsTwo(2) // Works!
    acceptsTwo(3) // Error!
    acceptsTwo('2') // Error!
    

    这种类型的用处很广泛,最常见的用法如下:

    // @flow
    function getColor(name: 'success' | 'warning' | 'danger') {
        switch (name) {
            case 'success': return 'green'
            case 'warning': return 'yellow'
            case 'danger': return 'red'
        }
    }
    acceptsTwo('success') // Works!
    acceptsTwo('danger') // Works!
    acceptsTwo('error') // Error!
    

    Mixed Types(混合类型)

    常见的三种类型

    一、单一类型

    如下示例中函数参数只能是数字

    // @flow
    function square (n: number) {
        return n * n
    }
    

    二、一组类型

    如下示例中参数可以是数字或者字符串

    // @flow
    function stringifyBasicValue (value: string | number) {
        return '' + value
    }
    

    三、依赖其他类型

    如下示例中将会返回一个类型,该类型与函数接收到的参数类型一致

    // @flow
    function identity<T>(value: T): T {
        return value;
    }
    

    任意类型

    使用mixed,表示可以是任意类型。

    // @flow
    function getTypeOf(value: mixed): string {
        return value;
    }
    

    注意:
    当使用mixed类型时,必须先计算传入参数的实际类型,然后再进行其他操作,否则将报错。

    示例一:不进行类型判断的情况会提示错误

    // @flow
    function stringify(value: mixed) {
        return value + ''; // Error!
    }
    stringify('foo')
    

    示例二:使用typeof value === 'string'进行类型校验时,flow可以知道在if中只接受string类型

    // @flow
    function stringify(value: mixed) {
        if(typeof value === 'string') {
            return value + ''
        } else {
            return ''
        }
    }
    stringify('foo')
    

    Any Types(任何类型)

    使用any类型是不安全的,应该尽可能的避免

    比如下面的代码,不会提示任何错误:

    // @flow
    function add(n: any, m: any):number {
        return n + m
    }
    add(1, 2) // Works
    add('1', '2') // Works
    add({}, []) // Works
    

    flow也不能捕捉到将会运行错误的代码

    // @flow
    function getNestedProperty(obj: any) {
        return obj.foo.bar.baz
    }
    getNestedProperty({})
    

    避免内存泄露问题

    当对一个类型为any的值进行操作时,flow会认为操作的执行结果类型也是any,再对结果进行操作,操作的新结果也会被认为是any类型。可以持续这个过程any类型出现在代码的所有位置

    如下示例,函数fn返回的结果类型为any,函数内部以及使用函数返回值的变量类型都为any

    // @flow
    function fn(obj: any) {
        let foo = obj.foo // foo类型为any
        let bar = foo * 2 // bar类型为any
        return bar
    }
    let bar = fn({foo: 2}) // bar类型为any
    let baz = 'baz:' + fn({foo: 2}) // baz类型为any
    

    可以使用快速定义其他类型的方式来解决上述问题
    如:

    // @flow
    function fn(obj: any) {
        let foo: number = obj.foo
        let bar = foo * 2 // bar类型为number
        return bar
    }
    let bar = fn({foo: 2}) // bar类型为number
    let baz = 'baz:' + fn({foo: 2}) // baz类型为string
    

    Maybe Types(可能类型)

    使用标志,表示该参数的类型可能是设置的类型,也可能是null或者undefined

    如:

    // @flow
    function acceptsMaybeNumber(n: ?number) {
        return n
    }
    acceptsMaybeNumber(2) // Works
    acceptsMaybeNumber(null) // Works
    acceptsMaybeNumber(undefined) // Works
    acceptsMaybeNumber() // Works
    acceptsMaybeNumber('234') // Error
    

    使用value != null可以同时排除undefinednull的值,也可以使用其他类似typeof的方式来校验排除

    Variable Types(变量类型)

    使用let或者var声明的变量可以被重新赋值,使用const声明的是常量,不可重新赋值

    const

    flow可以从值中提取类型,也可以给常量设置一个类型

    // @flow
    const foo: number = 2
    const foo = 2
    

    var let

    const类似,flow可以从值中提取类型,或者为变量设置一个类型

    // @flow
    let foo: number = 2
    let foo = 2
    

    当变量被设置类型时,修改变量必须可兼容的类型

    // @flow
    let foo: number = 2
    foo = 3 // Works!
    foo = '4' // Error!
    

    下面这些情况下,flow可以知道变量修改后的类型。

    // @flow
    let foo = 2
    let isNumber: number = foo // Works!
    
    foo = '4'
    let isString: string = foo
    

    if语句、函数和其他判断代码运行时jjiang hu将会阻止flow计算类型

    // @flow
    let foo = 42;
    function mutate() {
        foo = true;
        foo = "hello";
    }
    mutate();
    // $ExpectError
    let isString: string = foo; // Error!
    

    function Types(函数类型)

    函数可以设置两个地方的类型,一是接收的参数类型,二是返回的类型。

    // @flow
    function concat(a: string, b: string): string {
        return a + b;
    }
    concat("foo", "bar"); // Works!
    // $ExpectError
    concat(true, false);  // Error!
    

    函数声明

    有类型和无类型

    // @flow
    function method(str, bool, ...nums) {
        // ...
    }
    function method(str: string, bool: boolean, ...nums: Array<number>): void {
        // ...
    }
    

    箭头函数

    // @flow
    let method = (str, bool, ...nums) => {
        // ...
    }
    let method = (str: string, bool: boolean, ...nums: Array<number>): void => {
        // ...
    }
    

    函数类型

    1、常见写法

    (str: string, bool?: boolean, ...nums: Array<number>) => void
    

    2、可以省略参数名称

    (string, boolean | void,  Array<number>) => void
    

    3、也可以像回调函数一样使用这些函数类型

    function method(callback: (errpr: Error | null, value: string | null) => void {
        // ...
    }
    

    函数参数类型设置

    function method(param1: string, param2: number) {
        // ...
    }
    

    如果属性为可选项,可以使用在属性名后加?标记的形式进行标注。

    function method(param?: string) {
        // ...
    }
    

    此时,函数参数可以是空,undedined,以及符合类型的值,但是不支持null

    函数接收的参数组 arguments

    可以为函数接收的参数组指定类型,类型必须是数组,也可以为数组指定类型,如果示例,要求属性类型为数字

    function method(...args: Array<number>) {
        // ...
    }
    

    函数返回值的类型

    函数返回值类型可以确保函数的每个分支都返回相同的类型。

    function method(...args: Array<number>): number {
        // ...
    }
    

    this

    在flow中,不需要为this添加注释,flow会自动检查

    function method() {
        return this;
    }
    var num: number = method.call(42);
    // $ExpectError
    var str: string = method.call(42);
    

    函数内部判断

    在函数内部使用if条件判断语句时,直接使用if判断,flow会提示错误,需要使用flow提供%checks注释,如:

    function truthy(a, b): boolean %checks {
        return !!a && !!b;
    }
    function concat(a: ?string, b: ?string): string {
        if (truthy(a, b)) {
            return a + b;
        }
        return '';
    }
    

    Object Types(对象类型)

    基础语法

    使用花括号

    // @flow
    let obj1: {foo: boolean} = {foo: true}
    let obj2: {
        foo: number,
        bar: boolean
    } = {
        foo: 1,
        bar: true
    }
    

    可选的对象属性

    在js中访问对象不存在的属性,会提示错误,在flow中,同样会报错。

    为对象设置可选属性,如下示例,可选属性的值不可为null

    // @flow
    
    function acceptsObject(value: { foo?: string }) {
        // ...
    }
    acceptsObject({ foo: "bar" });     // Works!
    acceptsObject({ foo: undefined }); // Works!
    acceptsObject({ foo: null });      // Error!
    acceptsObject({});
    

    创建有属性的对象

    当创建一个带有属性的对象时,flow不允许添加新的属性,如下示例

    // @flow
    let obj = {
        foo: 1
    };
    // $ExpectError
    obj.bar = true;    // Error!
    // $ExpectError
    obj.baz = 'three'; // Error!
    

    没有任何属性的对象

    当创建一个没有任何属性的对象时,flow允许添加新的属性,且推断出新添加的属性类型

    // @flow
    let obj = {};
    obj.foo = 42;
    let num: number = obj.foo;
    

    注意:属性重新赋值时,flow也会重新计算类型。另外在这一类对象中查找未声明的属性是不安全的。

    确定的对象类型

    当对象的类型是确定时,不允许添加其他属性。

    // @flow
    // Error!
    let foo: {| foo: string |} = { foo: "Hello", bar: "World!" };
    

    Map Objects

    语法:

    // @flow
    let o : {[string]: number} = {}
    o['foo'] = 1
    o['bar'] = 2
    

    也可以为属性添加描述,如:

    // @flow
    let o : {[user_name: string]: number} = {}
    o['foo'] = 1
    o['bar'] = 2

    相关文章

      网友评论

        本文标题:Flow 文档记录

        本文链接:https://www.haomeiwen.com/subject/kqwxgftx.html