最近在一篇文章上看見了關(guān)于Flow的介紹,覺得它很不錯通贞,雖然之前在項目中使用Typescript已經(jīng)很順手了朗若,再使用Flow感覺有點累贅了,但多學(xué)點總是沒錯的昌罩。
簡介
JS作為一種腳本語言是沒有類型檢測的哭懈,這個特點有時候用著很爽,但當(dāng)你在一個較大的項目中的時候茎用,就會發(fā)現(xiàn)這其實是一件挺糟糕的事情遣总,因為和你協(xié)作的程序員往往不太清楚你所寫的代碼到底哪種類型才是正確的睬罗,而且代碼重構(gòu)的時候也很麻煩。于是基于這個需求有了Typescript和Flow的產(chǎn)生旭斥,今天這里主要介紹Flow容达。
安裝
因為筆者一直使用的是WebStorm,WebStorm內(nèi)部對Flow就有一定的支持垂券,所以如果你也使用WebStorm的話會方便很多董饰。
yarn add --dev flow-bin babel-cli babel-preset-flow
在安裝了上述的包之后,創(chuàng)建 .babelrc
文件:
{
"presets": ["flow"]
}
設(shè)置WebStorm
通過 File>Settings>Languages&Frameworks>JavaScript
如下圖所示設(shè)置圆米,F(xiàn)low package可以選擇你項目下的flow-bin卒暂,當(dāng)然你也可以全局安裝flow-bin,然后在這里設(shè)置后就可以在每個項目中都使用Flow了 娄帖。
flow不能直接在node或瀏覽器環(huán)境中使用也祠,所以我們必須用babel編譯后才能使用:
現(xiàn)在環(huán)境已經(jīng)快配好了,只剩最后一步近速,將一個此項目初始化為一個Flow項目:
yarn run flow init
現(xiàn)在當(dāng)我們在項目中使用Flow時WebStorm可以給出智能的提示了诈嘿。
使用
類型
最新的 ECMAScript 標(biāo)準(zhǔn)定義了 7 種數(shù)據(jù)類型:
在Flow中也是使用這幾種類型作為標(biāo)注:
使用原始類型:
// @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的構(gòu)造函數(shù)奖亚,是對象類型的。
Boolean
在Flow中析砸,默認(rèn)并不會轉(zhuǎn)換類型昔字,如果你需要轉(zhuǎn)換類型請使用顯示或隱式轉(zhuǎn)換,例如:
// @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
)來創(chuàng)建它們。
除了問號 ?
后跟著的類型弦疮,也許類型也可以是 null
或者 void
類型夹攒。
// @flow
function acceptsMaybeString(value: ?string) {
// ...
}
acceptsMaybeString("bar"); // Works!
acceptsMaybeString(undefined); // Works!
acceptsMaybeString(null); // Works!
acceptsMaybeString(); // Works!
可選的對象屬性
對象類型可以具有可選屬性,問號 ?
位于屬性名稱后面胁塞。
{ propertyName?: string }
除了它們的設(shè)定值類型之外咏尝,這些可選屬性也可以被 void
完全省略。但是啸罢,他們不能 null
编检。
// @flow
function acceptsObject(value: { foo?: string }) {
// ...
}
acceptsObject({ foo: "bar" }); // Works!
acceptsObject({ foo: undefined }); // Works!
acceptsObject({ foo: null }); // Error!
acceptsObject({}); // Works!
可選的函數(shù)參數(shù)
函數(shù)可以具有可選參數(shù),其中問號 ?
出現(xiàn)在參數(shù)名稱后面伺糠。同樣蒙谓,該參數(shù)不能為 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
- 數(shù)字:像
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是完全不安全的,應(yīng)盡可能避免置侍。
例如映之,下面的代碼不會報告任何錯誤:
// @flow
function add(one: any, two: any): number {
return one + two;
}
add(1, 2); // Works.
add("1", "2"); // Works.
add({}, []); // Works.
接口類型 interface
你可以使用 interface
以聲明您期望的類的結(jié)構(gòu)。
// @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蜡坊,你希望類匹配一個接口杠输。這可以防止編輯類時發(fā)生不兼容的更改。
// @flow
interface Serializable {
serialize(): string;
}
class Foo implements Serializable {
serialize() { return '[Foo]'; } // Works!
}
class Bar implements Serializable {
// $ExpectError
serialize() { return 42; } // Error!
}
數(shù)組類型 Array
要創(chuàng)建一個數(shù)組類型秕衙,可以使用 Array<Type>
類型蠢甲,其中 Type
是數(shù)組中元素的類型。例如据忘,為你使用的數(shù)字?jǐn)?shù)組創(chuàng)建一個類型 Array<number>
鹦牛。
let arr: Array<number> = [1, 2, 3];
暫時就介紹這么多,還有一些類型文章中沒有提到勇吊,更多更詳細(xì)的內(nèi)容請在Flow官網(wǎng)中查看曼追。