簡介
JavaScript作為一種腳本語言是沒有參數(shù)類型這個(gè)概念的,所以在編寫代碼的時(shí)候可以給參數(shù)賦予任何類型的值。在寫JS的時(shí)候不用考慮參數(shù)類型、參數(shù)定義等等概念。當(dāng)項(xiàng)目逐漸變大,人員逐漸變動(dòng)的時(shí)候,沒有任何參數(shù)類型再加上代碼命名不規(guī)范,代碼將變得十分難以維護(hù)。面對一個(gè)參數(shù)變量不知道它是用來做什么的??赡軙?huì)有如下代碼:
main = () => {
//fn1函數(shù)獲取了一個(gè)數(shù)據(jù)
var object = fn1()
//fn2根據(jù)獲數(shù)據(jù),產(chǎn)生一個(gè)結(jié)果
var result = fn2(object)
return result
}
Flow是個(gè)JavaScript的靜態(tài)類型檢查工具,所謂類型檢查,就是在編譯期盡早發(fā)現(xiàn)(由類型錯(cuò)誤引起的)bug,又不影響代碼運(yùn)行(不需要運(yùn)行時(shí)動(dòng)態(tài)檢查類型),使編寫 JavaScript 具有和編寫強(qiáng)類型語言相近的體驗(yàn)。
由于之前是寫Objective-C的,對于類型檢查還是比較能接受的。雖然在編寫代碼的時(shí)候會(huì)繁瑣一些,但是由于提前聲明了參數(shù)的類型,使用起來會(huì)更加的“放心”。
以下代碼實(shí)踐均在react native項(xiàng)目中實(shí)踐
安裝
npm install --save-dev flow-bin
創(chuàng)建配置文件。
touch .flowconfig
先不管空白的.flowconfig配置文件。在package.json文件里flow腳本。
your project/package.json
"scripts": {
"flow": "flow; test $? -eq 0 -o $? -eq 2",
},
然后給需要flow檢查的文件里加上//@flow或者/*@flow*/。然后就可以檢查了。(也可以在命令中加上--all, 這樣就會(huì)檢查所有文件)。
在根目錄下運(yùn)行命令:
npm run flow
以上就配置好了flow
使用
Flow最重要的功能就是允許在參數(shù)前添加類型注釋,即規(guī)定該參數(shù)的數(shù)據(jù)類型。Flow內(nèi)置了很多的數(shù)據(jù)類型,有些是給原生類型用的,像 number 和 string。 any 和 mixed 比較寬松,沒有把值的類型限定死,而其他字面類型則描述某一種類型。
基本數(shù)據(jù)類型
Flow中常用的基本數(shù)據(jù)類型有number、string、boolean
注意,這里的類型都是小寫開頭的
他們的用法大致相同。都是在參數(shù)中聲明該參數(shù)的類型,下面是一個(gè)使用number的例子。
// js
plus = (x, y) => {
return x + y;
}
// @flow
plus = (x: number, y: number) : number => {
return x + y;
}
plus(1, 2); // 正常返回3
plus('1', 2); // 報(bào)錯(cuò):Cannot call `plus` with `'1'` bound to `x` because string [1] is incompatible with number [2].
// 可以看到使用了Flow之后,當(dāng)傳入了不符合預(yù)先聲明的類型時(shí)Flow就會(huì)報(bào)錯(cuò),當(dāng)然這些錯(cuò)誤并不影響代碼的運(yùn)行。
// 不僅可以在定義函數(shù)的時(shí)候使用,而且可以在初始化變量的時(shí)候,就指定這個(gè)參數(shù)的類型,這和強(qiáng)類型語言的體驗(yàn)相似
let number1: number = 5;
let number2: number = '5'; // 報(bào)錯(cuò)
復(fù)合數(shù)據(jù)類型
Flow中也內(nèi)置了相關(guān)的復(fù)合數(shù)據(jù)類型,如Array、Object、Function
注意,這里的類型都是大寫開頭的
他們的使用方式和基礎(chǔ)數(shù)據(jù)類型差不多,不過Array在聲明的時(shí)候,不僅可以聲明這個(gè)參數(shù)是數(shù)組類型,還可以聲明這個(gè)數(shù)組里面的數(shù)據(jù)類型。
// @flow
let List1: Array<number> = [1];
let List2: Array<string> = ['21', '22'];
let List3: Array<boolean> = [false];
getFirst = (list: Array<number>) : number => {
return list[0];
}
任何數(shù)據(jù)類型
當(dāng)不確定一個(gè)參數(shù)的類型時(shí),可以使用mixed來聲明該參數(shù),但是在使用的時(shí)候必須要判斷這個(gè)參數(shù)的類型,否則Flow會(huì)報(bào)錯(cuò)。
// @flow
plus = (y: mixed) : number => {
if (typeof y === 'number') {
return y;
} else {
return 1;
}
}
// mixed是混合類型的意思
如果不希望這個(gè)參數(shù)被Flow檢查,可以使用any即任意類型。如果頻繁使用any來聲明參數(shù)類型,那么Flow就沒有任何意義了,盡量還是避免使用any。
枚舉類型
Flow支持自定義的一些參數(shù)類型,不僅僅局限于它內(nèi)置的幾個(gè)??梢允褂肍low輕松的實(shí)現(xiàn)一個(gè)枚舉類型。
// @flow
type myType = 'A' | 'B' | 'C';
let testType: myType = 'A';
// 定一個(gè)枚舉,聲明的參數(shù)如果是該枚舉類型,那么它的值一定是在枚舉類型中。
可選的參數(shù)類型
當(dāng)一個(gè)參數(shù)不確定是什么類型的時(shí)候,上述的mixed可以實(shí)現(xiàn)但是并不常用,通常使用的是|來聲明多個(gè)參數(shù)類型,或者使用?來代替mixed
// @flow
plus = (y: ?number) : number => {
if (typeof y === 'number') {
return y;
} else {
return 1;
}
}
// 這個(gè)?和mixed是一樣的,意思是這個(gè)參數(shù)可能是number類型,當(dāng)然也有可能是其他的類型。那么在使用的時(shí)候就需要對參數(shù)的類型判斷
// 如果參數(shù)的類型有兩個(gè),也就是說可能是number類型也可能是string類型,可以使用|來將所有的可能的參數(shù)類型列舉出來
plus = (y: number | string) : number => {
if (typeof y === 'number') {
return y;
} else {
return 1;
}
}
// 和上述的一樣,使用之前都需要判斷參數(shù)的類型才能使用
關(guān)于?的使用
Flow中的?有兩種使用方法,一個(gè)是在參數(shù)前表明這個(gè)參數(shù)是可選的,另一個(gè)是在數(shù)據(jù)類型前表示可能是這個(gè)參數(shù)類型,也可能是其他的類型。
// @flow
let number2: ?number = 43; // 意思是這個(gè)參數(shù)有可能是number類型
let string2: ?string = '12';
plus = (x?: number, y: number) : number => {
return x + y;
}
// 這里的?意思是這個(gè)x參數(shù)可能不存在
在React Native中使用
在React Native自定義組件的時(shí)候,F(xiàn)low可以用來聲明其需要的屬性,比如
// @flow
// 該組件的屬性
type Props = {
text?: string,
pointerEvents?: boolean,
timeout?: number,
onLoadingTimeout?: Function,
offsetY?: number,
};
// 組件
export default class Loading extends React.Component<Props> {
static defaultProps = {
pointerEvents: false,
timeout: 0,
offsetY: 0,
};
}
在自定義組件中不僅可以定義從父組件傳遞的參數(shù),還可以定義默認(rèn)屬性。其他的用法和上述用法是相同的。
總結(jié)
Flow本質(zhì)上也只是個(gè)檢查工具,它并不會(huì)自動(dòng)修正代碼中的錯(cuò)誤,也不會(huì)強(qiáng)制說你沒按照它的警告消息修正,就不會(huì)讓你運(yùn)行程序。當(dāng)然,并沒有要求什么時(shí)候一定要用這類的工具,只是這種作法可以讓你的代碼更具強(qiáng)健性與提高閱讀性,也可以直接避去很多不必要的數(shù)據(jù)類型使用上的問題,這種開發(fā)方式目前在許多框架與函數(shù)庫項(xiàng)目,或是以JavaScript應(yīng)用為主的開發(fā)團(tuán)隊(duì)中都已經(jīng)都是必用工具,在React、Vue源碼中均在使用。