资讯专栏INFORMATION COLUMN

JS 静态类型检查工具 Flow

CloudDeveloper / 2198人阅读

摘要:本文主要介绍了解决作为弱类型语言没有类型检查痛点的静态类型检查工具,并且介绍了在中使用的方法,最后介绍了一些常用的语法。

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

1. 简介

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

Flow是一个由Facebook出品的JavaScript静态类型检查工具,它与Typescript不同的是,它可以部分引入,不需要完全重构整个项目,所以对于一个已有一定规模的项目来说,迁移成本更小,也更加可行。除此之外,Flow可以提供实时增量的反馈,通过运行Flow server不需要在每次更改项目的时候完全从头运行类型检查,提高运行效率。Flow和Typescript都是给Javascript增加类型检查的优秀解决方案,两者的简单对比如下:

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

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

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

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

我是全局安装的:

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文件加入:

{
  "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:

在项目目录下运行flow init,会自动生成一个文件.flowconfig,这个文件可以配置flow,我的配置:

[ignore]
.*/node_modules/.*
/build/.*
/config/.*

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

现在当我们在项目中使用Flow时WebStorm可以给出智能的提示了。

并且多了一个窗口 Flow 给出文档中所有提示:

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 是数组中元素的类型。例如,为你使用的数字数组创建一个类型 Array

let arr: Array = [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:欢迎大家关注我的公众号【前端下午茶】,一起加油吧~

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

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/94209.html

相关文章

  • Flow - JS静态类型检查工具

    摘要:介绍是个的静态类型检查工具,由出品的开源码项目,问世只有一年多,是个相当年轻的项目。现在,提供了另一个新的选项,它是一种强静态类型的辅助检查工具。 showImg(https://segmentfault.com/img/bVH6mL?w=1200&h=675); 本章的目标是提供一些Flow工具的介绍与使用建议。Flow本质上也只是个检查工具,它并不会自动修正代码中的错误,也不会强制...

    seanHai 评论0 收藏0
  • 前端进阶(5) - js 扩展:静态类型检查(facebook flow

    摘要:扩展静态类型检查语言与系列等语言有一点很大的不同,就是语言是弱类型语言。但其实很多开发人员还是比较喜欢用来开发项目,所以开发出来帮助语言扩展静态类型检查功能,规避上面提到的问题。 js 扩展:静态类型检查(facebook flow) js 语言与 java、C 系列等语言有一点很大的不同,就是 js 语言是弱类型语言。js 语言的这个特性可能让大家觉得 js 很自由,没有强制性的约束...

    孙淑建 评论0 收藏0
  • JavaScript类型检查Flow

    摘要:一是一种弱类型动态类型检查的语言。动态类型与静态类型的核心区别动态类型的类型检查是是在代码运行的时候进行的,静态类型的类型检查则是在编译时进行。 一、js是一种弱类型、动态类型检查的语言。 弱类型:在定义变量时,可以为变量定义复制任何数据,变量的数据类型不是固定死的,这样的类型叫做弱类型。 var a = 10; a = abc; a = []; a = function() {}...

    zhonghanwen 评论0 收藏0
  • Flow, 一个新的Javascript静态类型检查

    摘要:原文链接翻译于今天我们兴奋的发布了的尝鲜版,一个新的静态类型检查器。为添加了静态类型检查,以提高开发效率和代码质量。这最终形成一个高度并行增量式的检查架构,类似。知道缩小类型范围时做动态检查的影响。 原文链接:https://code.facebook.com/posts/1505962329687926/flow-a-new-static-type-checker-for-java...

    liangzai_cool 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<