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:歡迎你們關注個人公衆號【前端下午茶】,一塊兒加油吧~

另外能夠加入「前端下午茶交流羣」微信羣,長按識別下面二維碼便可加我好友,備註加羣,我拉你入羣~

相關文章
相關標籤/搜索