最新公告
  • 欢迎您光临网站无忧模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • Flow:Facebook 的 JavaScript 静态类型检查器

    正文概述 掘金(同学小强)   2021-07-11   534

    Flow:Facebook 的 JavaScript 静态类型检查器

    JavaScript写起来,行云流水、挥洒自如、无拘无束、笔走龙蛇、为所欲为

    金主粑粑,每天抓狂,小修小补的hotfix从未停止脆弱的代码经不住半点风浪

    Flow:Facebook 的 JavaScript 静态类型检查器

    Flow是JavaScript代码的静态类型检查器。 它可以帮助您提高工作效率。 让您的代码更快,更智能,更自信,更大规模

    Flow通过静态类型注释检查代码是否存在错误。 这些类型允许您告诉Flow您希望代码如何工作,Flow将确保它以这种方式工作。

    1.从demo开始认识flow

    2.安装,配置

    3.flow总结及使用

    前言

    我们知道react源码现在还是采用flow + js的方式,下图截取一小段react Fiber源码,先混个脸熟

    /**
     * Copyright (c) Facebook, Inc. and its affiliates.
     *
     * This source code is licensed under the MIT license found in the
     * LICENSE file in the root directory of this source tree.
     *
     * @flow
     */
    import type {ReactElement} from 'shared/ReactElementType';
    import type {ReactFragment, ReactPortal, ReactScope} from 'shared/ReactTypes';
    import type {Fiber} from './ReactInternalTypes';
    import type {RootTag} from './ReactRootTags';
    import type {WorkTag} from './ReactWorkTags';
    import type {TypeOfMode} from './ReactTypeOfMode';
    import type {Lanes} from './ReactFiberLane.new';
    import type {SuspenseInstance} from './ReactFiberHostConfig';
    import type {OffscreenProps} from './ReactFiberOffscreenComponent';
    

    1.从demo开始认识flow

    1.1 出入参静态类型注释

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

    报错信息:

    Error ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ common/globFile.js:26:8

    Cannot call square with '2' bound to n because string [1] is incompatible with number [2].

    1.2.运算结果类型检查

    因为Flow很好地理解JavaScript,所以它不需要很多这些类型。 你应该只需要做很少的工作来描述你的Flow代码,它将推断其余部分。 在很多时候,Flow可以完全理解您的代码而不需要任何类型

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

    报错信息: Cannot perform arithmetic operation because string [1] is not a number.

    2.安装

    2.1 安装编译器

    官方推荐babelflow-remove-types

    npm install --save-dev @babel/cli @babel/preset-flow
    

    项目增加babel.config.js文件

    module.exports = function() {
      return {
        presets: [
          "@babel/preset-flow"
        ]
      }
    }
    

    package.json中添加scripts

    {
      "devDependencies": {
        "@babel/cli": "^7.4.4",
        "@babel/preset-flow": "^7.0.0",
      },
      "scripts": {
        "build": "babel src/ -d lib/",
        "prepublish": "npm run build"
      }
    }
    

    2.2 安装flow

    npm install --save-dev flow-bin
    

    package.json中添加scripts

    {
      "devDependencies": {
        "flow-bin": "^0.99.0"
      },
      "scripts": {
        "flow": "flow"
      }
    }
    

    生成flowconfig配置文件

    npm run flow init
    

    运行flow

    npm run flow
    

    3.flow总结及使用

    • 3.1 使用flow init初始化项目
    • 3.2 使用flow启动Flow后台进程flow status
    • 3.3 使用// @flow确定Flow将监视哪些文件
    • 3.4 编写flow代码
    • 3.5 检查代码是否存在类型错误
    • 3.6 如何在代码中添加类型注释

    3.1 使用 flow init 初始化项目

    生成类似INI格式,项目.flowconfig配置文件

    3.1.1 .flowconfig由6个部分组成

    ; 忽略匹配文件
    [ignore]
    <PROJECT_ROOT>/__tests__/.*
    <PROJECT_ROOT>/lib/.*
    
    ; 包含指定的文件或目录
    [include]
    <PROJECT_ROOT>/src/.*
    
    ; 在类型检查代码时包含指定的库定义
    [libs]
    
    ; lint
    [lints]
    all=warn
    untyped-type-import=error
    sketchy-null-bool=off
    
    ; 选项
    [options]
    all=true
    esproposal.decorators=ignore
    experimental.const_params=true
    module.file_ext=.bar
    module.use_strict=true
    
    ; 严格
    [strict]
    nonstrict-import
    unclear-type
    unsafe-getters-setters
    untyped-import
    untyped-type-import
    
    
    ; none
    ; 在声明模式下,代码没有进行类型检查,会检查文件内容
    [declarations]
    <PROJECT_ROOT>/third_party/.*
    
    ; 不检查文件内容,不匹配指定正则表达式的类型文件,丢弃类型并将模块视为任何模块
    [untyped]
    <PROJECT_ROOT>/third_party/.*
    
    ; 指定flow使用的版本
    [version]
    0.98.1
    
    

    3.1.2 # or ; or ? are ignored

    # This is a comment
      # This is a comment
    ; This is a comment
      ; This is a comment
    ? This is a comment
      ? This is a comment
    

    3.1.3 .flowconfig放置位置

    .flowconfig的位置非常重要。Flow将包含.flowconfig的目录视为项目根目录。 默认情况下,Flow包含项目根目录下的所有源代码

    3.2 使用flow启动flow后台进程

    vscode推荐安装Flow Language Support

    flow status // 启动flow后台进程
    flow stop   // 终止flow后台进程
    

    webpack热加载,使用flow-webpack-plugin

    'use strict';
    
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const path = require('path');
    const FlowWebpackPlugin = require('flow-webpack-plugin');
    
    module.exports = {
      mode: 'development',
      devtool: 'source-map',
      entry:  './example/app.js',
      output: {
          filename: 'bundle.js',
          path: path.resolve(__dirname, './dist'),
      },
      devServer: {
          hot: true,
          disableHostCheck: true,
          historyApiFallback: true
      },
      plugins: [
          new HtmlWebpackPlugin({ template: 'example/index.html' }),
          new FlowWebpackPlugin({
            flowArgs: ['check']
          })
      ],
    };
    

    3.3 使用// @flow确定Flow将监视哪些文件

    Flow后台进程使用此标志收集所有文件,并使用所有这些文件中提供的类型信息来确保一致性和无错误编程

    使用JavaScript注释的形式,注释@flow

    // @flow
    
    或
    
    /* @flow */
    

    忽略//@flow,检查所有文件

    flow check --all
    

    3.4 编写flow代码

    Flow后台进程将会捕获此错误

    // @flow
    
    function foo(x: ?number): string {
      if (x) {
        return x;
      }
      return "default string";
    }
    

    3.5 检查代码是否存在类型错误

    # equivalent to `flow status`
    flow
    

    运行flow检查

    // @flow
    
    function foo(x: ?number): string {
      if (x) {
        return x;  // Cannot return `x` because  number [1] is incompatible with  string [2].
      }
      return "default string";
    }
    

    3.6 如何在代码中添加类型注释

    类型注释符号

    |       // 或
    &       // 且 
    ?       // 可选
    

    类型注释中包括的类型

    boolean                                 // true or new Boolean(false)
    string                                  // "hello" or new String("world")
    number                                  // 3.14 or new Number(42)
    null                                    // null
    undefined (void in Flow types)          // undefined
    Array (其中T用来描述数组中值的类型)     // Array<T>
    Object                                  // {}
    Function                                // function
    class                                   // class
    Symbols (not yet supported in Flow)     // Symbol("foo")
    

    小写

    // @flow
    function method(x: number, y: string, z: boolean) {
      // ...
    }
    
    method(3.14, "hello", true);
    

    大写

    // @flow
    function method(x: Number, y: String, z: Boolean) {
      // ...
    }
    
    method(new Number(42), new String("world"), new Boolean(false));
    

    boolean

    // @flow
    function acceptsBoolean(value: boolean) {
      // ...
    }
    
    acceptsBoolean(true);  // Works!
    acceptsBoolean(false); // Works!
    acceptsBoolean("foo"); // Error!
    

    JavaScript可以隐式地将其他类型的值转换为布尔值

    if (42) {} // 42 => true
    if ("") {} // "" => false
    

    非布尔值需要显式转换为布尔类型

    // @flow
    function acceptsBoolean(value: boolean) {
      // ...
    }
    
    acceptsBoolean(0);          // Error!
    acceptsBoolean(Boolean(0)); // Works!
    acceptsBoolean(!!0);        // Works!
    

    string

    // @flow
    function acceptsString(value: string) {
      // ...
    }
    
    acceptsString("foo"); // Works!
    acceptsString(false); // Error!
    

    JavaScript可以隐式地将其他类型的值转换为字符

    "foo" + 42; // "foo42"
    "foo" + {}; // "foo[object Object]"
    

    Flow连接到字符串时只接受字符串和数字。

    // @flow
    "foo" + "foo"; // Works!
    "foo" + 42;    // Works!
    "foo" + {};    // Error!
    "foo" + [];    // Error!
    

    必须明确并将其他类型转换为字符串

    // @flow
    "foo" + String({});     // Works!
    "foo" + [].toString();  // Works!
    "" + JSON.stringify({}) // Works!
    

    number

    // @flow
    function acceptsNumber(value: number) {
      // ...
    }
    
    acceptsNumber(42);       // Works!
    acceptsNumber(3.14);     // Works!
    acceptsNumber(NaN);      // Works!
    acceptsNumber(Infinity); // Works!
    acceptsNumber("foo");    // Error!
    

    null and void

    // @flow
    function acceptsNull(value: null) {
      /* ... */
    }
    
    function acceptsUndefined(value: void) {
      /* ... */
    }
    
    acceptsNull(null);           // Works!
    acceptsNull(undefined);      // Error!
    acceptsUndefined(null);      // Error!
    acceptsUndefined(undefined); // Works!
    

    Array

    let arr: Array<number> = [1, 2, 3];
    let arr1: Array<boolean> = [true, false, true];
    let arr2: Array<string> = ["A", "B", "C"];
    let arr3: Array<mixed> = [1, true, "three"]
    

    Object

    // @flow
    var obj1: { foo: boolean } = { foo: true };
    var obj2: {
      foo: number,
      bar: boolean,
      baz: string,
    } = {
      foo: 1,
      bar: true,
      baz: 'three',
    };
    

    Function

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

    箭头Function

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

    回调Function

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

    class

    // @flow
    class MyClass<A, B, C> {
      constructor(arg1: A, arg2: B, arg3: C) {
        // ...
      }
    }
    
    var val: MyClass<number, boolean, string> = new MyClass(1, true, 'three');
    
    
    class Foo {
      serialize() { return '[Foo]'; }
    }
    
    class Bar {
      serialize() { return '[Bar]'; }
    }
    
    // $ExpectError
    const foo: Foo = new Bar(); // Error!
    

    Maybe Types

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

    对象属性可选

    // @flow
    function acceptsObject(value: { foo?: string }) {
      // ...
    }
    
    acceptsObject({ foo: "bar" });     // Works!
    acceptsObject({ foo: undefined }); // Works!
    acceptsObject({ foo: null });      // Error!问号放在string前不报错
    acceptsObject({});                 // Works!
    

    函数参数可选

    // @flow
    function acceptsOptionalString(value?: string) {
      // ...
    }
    
    acceptsOptionalString("bar");     // Works!
    acceptsOptionalString(undefined); // Works!
    acceptsOptionalString(null);      // Error!问号放在string前不报错
    acceptsOptionalString();          // Works!
    

    带默认值的函数参数

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

    使用字面文字作为类型

    // @flow
    function acceptsTwo(value: 2) {
      // ...
    }
    
    acceptsTwo(2);   // Works!
    // $ExpectError
    acceptsTwo(3);   // Error!
    // $ExpectError
    acceptsTwo("2"); // Error!
    

    Union Types

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

    Mixed Types

    function stringifyBasicValue(value: string | number) {
      return '' + value;
    }
    

    A type based on another type

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

    An arbitrary type that could be anything

    function getTypeOf(value: mixed): string {
      return typeof value;
    }
    

    Any Types

    // @flow
    function add(one: any, two: any): number {
      return one + two;
    }
    
    add(1, 2);     // Works.
    add("1", "2"); // Works.
    add({}, []);   // Works.
    

    变量类型 将类型添加到变量声明 const let var

    // @flow
    const foo /* : number */ = 1;
    const bar: number = 2;
    
    var fooVar /* : number */ = 1;
    let fooLet /* : number */ = 1;
    var barVar: number = 2;
    let barLet: number = 2;
    

    let

    let foo: number = 1;
    foo = 2;   // Works!
    // $ExpectError
    foo = "3"; // Error!
    

    重新分配变量

    let foo = 42;
    
    if (Math.random()) foo = true;
    if (Math.random()) foo = "hello";
    
    let isOneOf: number | boolean | string = foo; // Works!
    

    重新分配变量确定变量类型

    // @flow
    let foo = 42;
    let isNumber: number = foo; // Works!
    
    foo = true;
    let isBoolean: boolean = foo; // Works!
    
    foo = "hello";
    let isString: string = foo; // Works!
    

    react

    import * as React from 'react';
    
    type Props = {
      foo: number,
      bar?: string,
    };
    
    type State = {
      count: number,
    };
    
    
    class MyComponent extends React.Component<Props> {
      state = {
        count: 0,
      };
      render() {
        this.props.doesNotExist; // Error! You did not define a `doesNotExist` prop.
    
        return <div>{this.props.bar}</div>;
      }
    }
    
    <MyComponent foo={42} />;
    

    想了解更多用法,可移步flow官方文档:flow.org

    此篇笔记已收录 个人笔记,感谢阅读,欢迎star鼓励


    下载网 » Flow:Facebook 的 JavaScript 静态类型检查器

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元