
JavaScript写起来,行云流水、挥洒自如、无拘无束、笔走龙蛇、为所欲为
金主粑粑,每天抓狂,小修小补的hotfix从未停止,脆弱的代码经不住半点风浪

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 安装编译器
官方推荐babel或flow-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鼓励
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
 - 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
 
- 提示下载完但解压或打开不了?
 
- 找不到素材资源介绍文章里的示例图片?
 
- 模板不会安装或需要功能定制以及二次开发?
 
                    
    
发表评论
还没有评论,快来抢沙发吧!