JS 静态类型检查工具 Flow

本文主要介绍了解决JS做为弱类型语言没有类型检查痛点的静态类型检查工具 Flow ,而且介绍了在WebStorm中使用Flow的方法,最后介绍了一些经常使用的Flow语法。前端

1. 简介

JS做为一种脚本语言是没有类型检测的,这个特色有时候用着很方便,但在一个较大的项目中就会发现这实际上是一件挺糟糕的特性,由于和你协做的程序员每每不太清楚你所写的代码到底哪一种类型才是正确的,等到代码重构就比较麻烦。因而基于这个需求有了Typescript和Flow的产生,今天这里主要介绍Flowvue

Flow是一个由Facebook出品的JavaScript静态类型检查工具,它与Typescript不一样的是,它能够部分引入,不须要彻底重构整个项目,因此对于一个已有必定规模的项目来讲,迁移成本更小,也更加可行。除此以外,Flow能够提供实时增量的反馈,经过运行Flow server不须要在每次更改项目的时候彻底从头运行类型检查,提升运行效率。Flow和Typescript都是给Javascript增长类型检查的优秀解决方案,二者的简单对好比下:node

工具 Flow TypeScript
公司 Facebook 微软
star 16k 33k
文档支持程度 中等
优势 自由度高,老项目迁移成本低 工程化强,社区活跃,官方支持力度高

对于二者使用场景差异,能够简单总结为:对于新项目,能够考虑使用TypeScript或者Flow,对于已有必定规模的项目则建议使用Flow进行较小成本的逐步迁移来引入类型检查。Flow能够帮助找出因为不合理的类型操做引发的错误,包括运算符操做,函数参数类型和返回值类型等。Flow也支持自定义类型声明,泛型声明等类型语言相关的操做,详细的内容能够参考文档webpack

引入方法:在须要使用 Flow 进行类型检查的 js 文件开头加入 // @flow 或者 /* @flow */,便可引入Flow,一个简单例子:git

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

square("2"); // Error!

2. 安装方法

npm安装:程序员

npm install --save-dev babel-cli babel-preset-flow flow-babel-webpack-plugin babel-preset-es2015 babel-preset-env babel-plugin-transform-class-properties

我是全局安装的:github

npm install -g babel-cli babel-preset-flow flow-bin flow-babel-webpack-plugin babel-preset-es2015  babel-preset-env babel-plugin-transform-class-properties

.babelrc文件加入:web

{
  "presets": ["flow", "es2015"],
  "plugins": [
    "transform-vue-jsx",
    "transform-runtime",
    "transform-class-properties"
  ]
}

设置一下WebStorm:经过 File>Settings>Languages&Frameworks>JavaScript 选择Flow,Flow package能够选择你项目下的flow-bin,固然你也能够全局安装flow-bin,而后在这里设置后就能够在每一个项目中都使用Flow了 。
可是flow不能直接在node或浏览器环境中使用,因此咱们必须用babel编译后才能使用,使用File watcher:npm

clipboard.png

在项目目录下运行flow init,会自动生成一个文件.flowconfig,这个文件能够配置flow,个人配置:segmentfault

[ignore]
.*/node_modules/.*
<PROJECT_ROOT>/build/.*
<PROJECT_ROOT>/config/.*

[options]
module.file_ext=.js
module.file_ext=.vue

如今当咱们在项目中使用Flow时WebStorm能够给出智能的提示了。

clipboard.png

而且多了一个窗口 Flow 给出文档中全部提示:

clipboard.png

3. 使用

最新的 ECMAScript 标准定义了 7 种数据类型: 6种原始类型:Boolean、Null、Undefined、Number、String、Symbol 和 Object

在Flow中也是使用这几种类型做为标注:

使用原始类型:

// @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));

这里须要注意的是大小写,小写的 number 是原始类型,而大写的 Number 是JavaScript的构造函数,是对象类型的。

Boolean

在Flow中,默认并不会转换类型,若是你须要转换类型请使用显示或隐式转换,例如:

// @flow
function acceptsBoolean(value: boolean) {
  // ...
}

acceptsBoolean(true); // Works!
acceptsBoolean(false); // Works!
acceptsBoolean("foo"); // Error!
acceptsBoolean(Boolean("foo")); // Works!
acceptsBoolean(!!("foo")); // Works!

Number

// @flow
function acceptsNumber(value: number) {
  // ...
}

acceptsNumber(42); // Works!
acceptsNumber(3.14); // Works!
acceptsNumber(NaN); // Works!
acceptsNumber(Infinity); // Works!
acceptsNumber("foo"); // Error!

null和void

JavaScript兼有 null 和 undefined。Flow将这些视为单独的类型:null 和 void(void表示undefined类型)

// @flow
function acceptsNull(value: null) {
  /* ... */
}

function acceptsUndefined(value: void) {
  /* ... */
}

acceptsNull(null); // Works!
acceptsNull(undefined); // Error!
acceptsUndefined(null); // Error!
acceptsUndefined(undefined); // Works!

也许类型

也许类型是用于可选值的地方,你能够经过在类型前添加一个问号(如 ?string 或者 ?number)来建立它们。

除了问号 ? 后跟着的类型,也许类型也能够是 null 或者 void 类型。

// @flow
function acceptsMaybeString(value: ?string) {
  // ...
}

acceptsMaybeString("bar"); // Works!
acceptsMaybeString(undefined); // Works!
acceptsMaybeString(null); // Works!
acceptsMaybeString(); // Works!

可选的对象属性

对象类型能够具备可选属性,问号 ? 位于属性名称后面。

{ propertyName?: string }

除了它们的设定值类型以外,这些可选属性也能够被 void 彻底省略。可是,他们不能 null。

// @flow
function acceptsObject(value: { foo?: string }) {
  // ...
}

acceptsObject({ foo: "bar" }); // Works!
acceptsObject({ foo: undefined }); // Works!
acceptsObject({ foo: null }); // Error!
acceptsObject({}); // Works!

可选的函数参数

函数能够具备可选参数,其中问号 ? 出如今参数名称后面。一样,该参数不能为 null。

// @flow
function acceptsOptionalString(value?: string) {
  // ...
}

acceptsOptionalString("bar"); // Works!
acceptsOptionalString(undefined); // Works!
acceptsOptionalString(null); // Error!
acceptsOptionalString(); // Works!

文字类型

文字类型使用一个具体的值做为类型:

function foo(value: 2) {}

foo(2); // Work!
foo(3); // Error!
foo('2'); // Error!

您可使用这些类型的原始值:

  • 布尔值: true 或 false
  • 数字:像 42 或 3.14
  • 字符串:像 "foo" 或 "bar"
// @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

有时候咱们并不能肯定须要的值究竟是哪一种类型,这时候咱们可使用混合类型来表示,但在使用该值以前,咱们须要判断该值究竟是哪一种类型,不然会引发错误:

// @flow
function stringify(value: mixed) {
  // $ExpectError
  return "" + value; // Error!
}

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

stringify("foo");

任意类型 any

若是你想要一种方法来选择不使用类型检查器,any 是作到这一点的方法。使用any是彻底不安全的,应尽量避免。

例如,下面的代码不会报告任何错误:

// @flow
function add(one: any, two: any): number {
  return one + two;
}

add(1, 2); // Works.
add("1", "2"); // Works.
add({}, []); // Works.

接口类型 interface

你可使用 interface 以声明您指望的类的结构。

// @flow
interface Serializable {
  serialize(): string;
}

class Foo {
  serialize() { return '[Foo]'; }
}

class Bar {
  serialize() { return '[Bar]'; }
}

const foo: Serializable = new Foo(); // Works!
const bar: Serializable = new Bar(); // Works!

你也可使用 implements 告诉Flow,你但愿类匹配一个接口。这能够防止编辑类时发生不兼容的更改。

// @flow
interface Serializable {
  serialize(): string;
}

class Foo implements Serializable {
  serialize() { return '[Foo]'; } // Works!
}

class Bar implements Serializable {
  // $ExpectError
  serialize() { return 42; } // Error!
}

数组类型 Array

要建立一个数组类型,可使用 Array<Type> 类型,其中 Type 是数组中元素的类型。例如,为你使用的数字数组建立一个类型 Array<number>

let arr: Array<number> = [1, 2, 3];

暂时就介绍这么多,还有一些类型文章中没有提到,更多更详细的内容请在Flow官网中查看。

4. 移除Flow内容

由于Flow的语法并非标准的JavaScript语法,因此咱们要在代码最终上线前移除Flow相关的代码(主要是那些固定类型的描述,若是只是添加了@flow,直接应用便可)

flow-remove-types

这个程序会将你全部标有@flow的内容进行移除。。而后将移除后的代码生成后指定的目录下

npm i -g flow-remove-types
flow-remove-types src/ --out-dir dist/
# src 源文件地址
# dist 生成后的地址

babel+webpack

安装一个webpack插件

npm i -D flow-babel-webpack-plugin

而后咱们修改 .babelrc 文件,添加以下配置:

{
  "plugins": [
      "transform-flow-comments"
  ]
}

而后在webpack.config.jswebpack.dev.config.jswebpack.prod.config.js、文件中添加:

const FlowBabelWebpackPlugin= require('flow-babel-webpack-plugin')
module.exports = {
  plugins: [
      new FlowBabelWebpackPlugin()
  ]
}

在babel编译JavaScript的同时也就会将Flow内容进行移除了。


网上的帖子大多深浅不一,甚至有些先后矛盾,在下的文章都是学习过程当中的总结,若是发现错误,欢迎留言指出~

参考:
使用Flow来检测你的JS
vue2.0项目配置flow类型检查
用flow.js提高前端开发的体验
Flow静态类型检查及在Vue项目中的使用
如何在项目中使用 flow js

PS:欢迎你们关注个人公众号【前端下午茶】,一块儿加油吧~

另外能够加入「前端下午茶交流群」微信群,长按识别下面二维码便可加我好友,备注加群,我拉你入群~

相关文章
相关标签/搜索