摘要:介紹是個(gè)的靜態(tài)類(lèi)型檢查工具,由出品的開(kāi)源碼項(xiàng)目,問(wèn)世只有一年多,是個(gè)相當(dāng)年輕的項(xiàng)目?,F(xiàn)在,提供了另一個(gè)新的選項(xiàng),它是一種強(qiáng)靜態(tài)類(lèi)型的輔助檢查工具。
本章的目標(biāo)是提供一些Flow工具的介紹與使用建議。Flow本質(zhì)上也只是個(gè)檢查工具,它并不會(huì)自動(dòng)修正代碼中的錯(cuò)誤,也不會(huì)強(qiáng)制說(shuō)你沒(méi)按照它的警告消息修正,就不會(huì)讓你運(yùn)行程序。當(dāng)然,并沒(méi)有要求什么時(shí)候一定要用這類(lèi)的工具,只是這種作法可以讓你的代碼更具強(qiáng)健性與提高閱讀性,也可以直接避去很多不必要的數(shù)據(jù)類(lèi)型使用上的問(wèn)題,這種開(kāi)發(fā)方式目前在許多框架與函數(shù)庫(kù)項(xiàng)目,或是以JavaScript應(yīng)用為主的開(kāi)發(fā)團(tuán)隊(duì)中都已經(jīng)都是必用工具。
注意注: 本文內(nèi)容大部份參考自Flow官網(wǎng),是之前我個(gè)人博客文章 - "Flow靜態(tài)數(shù)據(jù)類(lèi)型的檢查工具,10分鐘快捷入門(mén)"的增修版本。
注: 本文內(nèi)容字?jǐn)?shù)過(guò)萬(wàn),去除代碼也有數(shù)千字,筆誤在所難免,有錯(cuò)再回饋留言吧。
"奇異博士"說(shuō)過(guò)「使用警語(yǔ)應(yīng)該要加注在書(shū)的最前面」。所以我把注意項(xiàng)目先加在這里。
由于Flow還是個(gè)年輕的項(xiàng)目,問(wèn)題仍然很多,功能也沒(méi)你想像中完整,用起來(lái)有時(shí)候會(huì)卡頓是正常的,效能仍須改善。以后用戶愈來(lái)愈多就會(huì)愈作愈好。
Windows平臺(tái)的支持也是幾個(gè)月前(2016.8)時(shí)的事,F(xiàn)low只支持64位元的作業(yè)系統(tǒng),32位元就不能用了。
如果你是要學(xué)或用React或Vue.js等等,F(xiàn)low是必學(xué)的。不管你要用不用,庫(kù)源碼里面都用了。
Flow介紹Flow是個(gè)JavaScript的靜態(tài)類(lèi)型檢查工具,由Facebook出品的開(kāi)源碼項(xiàng)目,問(wèn)世只有一年多,是個(gè)相當(dāng)年輕的項(xiàng)目。簡(jiǎn)單來(lái)說(shuō),它是對(duì)比TypeScript語(yǔ)言的解決方式。
會(huì)有這類(lèi)解決方案,起因是JavaScript是一種弱(動(dòng)態(tài))數(shù)據(jù)類(lèi)型的語(yǔ)言,弱(動(dòng)態(tài))數(shù)據(jù)類(lèi)型代表在代碼中,變量或常量會(huì)自動(dòng)依照賦值變更數(shù)據(jù)類(lèi)型,而且類(lèi)型種類(lèi)也很少,這是直譯式腳本語(yǔ)言的常見(jiàn)特性,但有可能是優(yōu)點(diǎn)也是很大的缺點(diǎn)。優(yōu)點(diǎn)是容易學(xué)習(xí)與使用,缺點(diǎn)是像開(kāi)發(fā)者經(jīng)常會(huì)因?yàn)橘x值或傳值的類(lèi)型錯(cuò)誤,造成不如預(yù)期的結(jié)果。有些時(shí)候在使用框架或函數(shù)庫(kù)時(shí),如果沒(méi)有仔細(xì)看文件,亦或是文件寫(xiě)得不清不楚,也容易造成誤用的情況。
這個(gè)缺點(diǎn)在應(yīng)用規(guī)?;瘯r(shí),會(huì)顯得更加嚴(yán)重。我們?cè)陂_(kāi)發(fā)團(tuán)隊(duì)的協(xié)同時(shí),一般都是用詳盡的文字說(shuō)明,來(lái)降低這個(gè)問(wèn)題的發(fā)生,但JS語(yǔ)言本身無(wú)法有效阻止這些問(wèn)題。而且說(shuō)明文件也需要花時(shí)間額外編寫(xiě),其他的開(kāi)發(fā)者閱讀也需要花時(shí)間。在現(xiàn)今預(yù)先編譯器流行的年代,像TypeScript這樣的強(qiáng)(靜態(tài))類(lèi)的JavaScript超集語(yǔ)言就開(kāi)始流行,用嚴(yán)格的角度,以JavaScript語(yǔ)言為基底,來(lái)重新打造另一套具有強(qiáng)(靜態(tài))類(lèi)型特性的語(yǔ)言,就如同Java或C#這些語(yǔ)言一樣,這也是為什么TypeScript稱(chēng)自己是企業(yè)級(jí)的開(kāi)發(fā)JavaScript解決方案。
注: 強(qiáng)(靜態(tài))類(lèi)型語(yǔ)言,意思是可以讓變量或常量在聲明(定義)時(shí),就限制好只能使用哪種類(lèi)型,之后在使用時(shí)如果發(fā)生類(lèi)型不相符時(shí),就會(huì)發(fā)出錯(cuò)誤警告而不能編譯。但不只這些,語(yǔ)言本身也會(huì)拓展了更多的類(lèi)型與語(yǔ)法。
TypeScript自然有它的市場(chǎng),但它有一些明顯的問(wèn)題,首先是JavaScript開(kāi)發(fā)者需要再進(jìn)一步學(xué)習(xí),內(nèi)容不少,也有一定陡峭的學(xué)習(xí)曲線,不過(guò)這還算小事情。重大的事情是需要把已經(jīng)在使用的應(yīng)用代碼,都要整個(gè)改用TypeScript代碼語(yǔ)法,才能發(fā)揮完整的功用。這對(duì)很多已經(jīng)有內(nèi)部代碼庫(kù)的大型應(yīng)用開(kāi)發(fā)團(tuán)隊(duì)而言,將會(huì)是個(gè)重大的決定,因?yàn)槿绻煌嬷貥?gòu)的路走,將無(wú)法發(fā)揮強(qiáng)(靜態(tài))類(lèi)型語(yǔ)言的最大效用。
所以許多現(xiàn)行的開(kāi)源碼函數(shù)庫(kù)或框架,并不會(huì)直接使用TypeScript作為代碼的語(yǔ)言,另一方面當(dāng)然因?yàn)槭荰ypeScript并非普及到一定程度的語(yǔ)言,社群上有熱愛(ài)的粉絲也有不是那么支持的反對(duì)者。當(dāng)然,TypeScript也有它的優(yōu)勢(shì),自從TypeScript提出了DefinitelyTyped的解決方式之后,讓現(xiàn)有的函數(shù)庫(kù)能額外再定義出里面使用的類(lèi)型,這也是另一個(gè)可以與現(xiàn)有框架與庫(kù)相整合的方案,這讓許多函數(shù)庫(kù)與框架都提交定義檔案,提供了另一種選擇。另一個(gè)優(yōu)勢(shì)是,TypeScript也是個(gè)活躍的開(kāi)源碼項(xiàng)目,發(fā)展到現(xiàn)在也有一段時(shí)間,算是逐漸成熟的項(xiàng)目。它的背后有微軟公司的支持,在最近發(fā)布的知名的、全新打造過(guò)的Angular2框架中(由Google主導(dǎo)),也采用了TypeScript作為基礎(chǔ)的開(kāi)發(fā)語(yǔ)言。
現(xiàn)在,F(xiàn)low提供了另一個(gè)新的選項(xiàng),它是一種強(qiáng)(靜態(tài))類(lèi)型的輔助檢查工具。Flow的功能是讓現(xiàn)有的JavaScript語(yǔ)法可以事先作類(lèi)型的聲明(定義),在開(kāi)發(fā)過(guò)程中進(jìn)行自動(dòng)檢查,當(dāng)然在最后編譯時(shí),一樣可以用babel工具來(lái)移除這些標(biāo)記。
相較于TypeScript是另外重新制定一套語(yǔ)言,最后再經(jīng)過(guò)編譯為JavaScript代碼來(lái)運(yùn)行。Flow走的則是非強(qiáng)制與非侵入性的路線。Flow的優(yōu)點(diǎn)是易學(xué)易用,它的學(xué)習(xí)曲線沒(méi)有TypeScript來(lái)得高,雖然內(nèi)容也很多,但大概一天之內(nèi)學(xué)個(gè)大概,就可以漸進(jìn)式地開(kāi)始使用。而且因?yàn)镕low從頭到尾只是個(gè)檢查工具,并不是新的程序語(yǔ)言或超集語(yǔ)言,所以它可以與各種現(xiàn)有的JavaScript代碼兼容,如果你哪天不想用了,就去除掉標(biāo)記就是回到原來(lái)的代碼,沒(méi)什么負(fù)擔(dān)。當(dāng)然,F(xiàn)low的功用可能無(wú)法像TypeScript這么全面性,也不可能改變要作某些事情的語(yǔ)法結(jié)構(gòu)。
總結(jié)來(lái)說(shuō),這兩種方式的目的是有些相似的,各自有優(yōu)點(diǎn)也有不足之處,青菜蘿卜各有所愛(ài),要選擇哪一種方式就看你的選擇。
從一個(gè)小例子演示這種類(lèi)型不符的情況在代碼中非常容易發(fā)生,例如以下的例子:
function foo(x) { return x + 10 } foo("Hello!")
x這個(gè)傳參,我們?cè)诤瘮?shù)聲明時(shí)希望它是個(gè)數(shù)字類(lèi)型,但最后使用調(diào)用函數(shù)時(shí)則用了字符串類(lèi)型。最后的結(jié)果會(huì)是什么嗎? "Hello!10",這是因?yàn)榧犹?hào)(+)在JavaScript語(yǔ)言中,除了作為數(shù)字的加運(yùn)算外,也可以當(dāng)作字符串的連接運(yùn)算。想當(dāng)然這并不是我們想要的結(jié)果。
聰明如你應(yīng)該會(huì)想要用類(lèi)型來(lái)當(dāng)傳參的識(shí)別名,容易一眼看出傳參要的是什么類(lèi)型,像下面這樣:
function foo(number) { return number + 10 }
但如果在復(fù)合類(lèi)型的情況,例如這個(gè)傳參的類(lèi)型可以是數(shù)字類(lèi)型也可以是布爾類(lèi)型,你又要如何寫(xiě)得清楚?更不用說(shuō)如果是個(gè)復(fù)雜的對(duì)象類(lèi)型時(shí),結(jié)構(gòu)又該如何先確定好?另外還有函數(shù)的返回類(lèi)型又該如何來(lái)寫(xiě)?
利用Flow類(lèi)型的定義方式,來(lái)解決這個(gè)小案例的問(wèn)題,可以改寫(xiě)為像下面的代碼:
// @flow function foo(x: number): number { return x + 10 } foo("hi")
你有看到在函數(shù)的傳參,以及函數(shù)的圓括號(hào)(())后面的兩個(gè)地方,加了: number標(biāo)記,這代表這個(gè)傳參會(huì)限定為數(shù)字類(lèi)型,而返回值也只允許是數(shù)字類(lèi)型。
當(dāng)使用非數(shù)字類(lèi)型的值作為傳入值時(shí),就會(huì)出現(xiàn)由Flow工具發(fā)出的警告消息,像下面這樣:
message: "[flow] string (This type is incompatible with number See also: function call)"
這消息是說(shuō),你這函數(shù)的傳參是string(字符串)類(lèi)型,與你聲明的number(數(shù)字)不相符合。
如果是要允許多種類(lèi)型也是很容易可以加標(biāo)記的,假使這個(gè)函數(shù)可以使用布爾與數(shù)字類(lèi)型,但返回可以是數(shù)字或字符串,就像下面這樣修改過(guò):
// @flow function foo(x: number | boolean): number | string { if (typeof x === "number") { return x + 10 } return "x is boolean" } foo(1) foo(true) foo(null) // 這一行有類(lèi)型錯(cuò)誤消息
由上面這個(gè)小例子你可以想見(jiàn),如果在多人協(xié)同開(kāi)發(fā)某個(gè)有規(guī)模的JavaScript應(yīng)用時(shí),這種類(lèi)型的輸出輸入問(wèn)題就會(huì)很常遇見(jiàn)。如果利用Flow工具的檢查,可以避免掉許多不必要的類(lèi)型問(wèn)題。
真實(shí)案例可能你會(huì)認(rèn)為Flow工具只能運(yùn)用在小型代碼中,但實(shí)際上Facebook會(huì)創(chuàng)造出Flow工具,有很大的原因是為了React與React Native。
舉一個(gè)我最近正在研究的的函數(shù)庫(kù)代碼中NavigationExperimental(這網(wǎng)址位置有可能會(huì)變,因?yàn)槭侵苯舆B到源碼里),這里面就預(yù)先聲明了所有的對(duì)象結(jié)構(gòu),像下面這樣的代碼:
export type NavigationGestureDirection = "horizontal" | "vertical"; export type NavigationRoute = { key: string, title?: string }; export type NavigationState = { index: number, routes: Array, }; // ...
Flow具備有像TypeScript語(yǔ)言中,預(yù)先定義對(duì)象類(lèi)型的作用。上面代碼的都是這個(gè)組件中預(yù)先定義的類(lèi)型,這些類(lèi)型可以再套用到不同的代碼文檔之中。
export type NavigationGestureDirection = "horizontal" | "vertical";
上面這行類(lèi)似于列舉(enum)的類(lèi)型,意思是說(shuō)要不就是"horizontal"(水平的),要不然就"vertical"(垂直的),就這兩種字符串值可使用。
export type NavigationRoute = { key: string, title?: string };
這行里面用了一個(gè)問(wèn)號(hào)(?)定義在title屬性的后面,這代表這屬性是可選的(Optional),不過(guò)你可能會(huì)有點(diǎn)搞混,因?yàn)閱?wèn)號(hào)(?)可以放在兩個(gè)位置,見(jiàn)下面的例子:
export type Test = { titleOne?: string, titleTwo: ?string }
titleOne代表的是屬性為可自定義的(可有可無(wú)),但一定是字符串類(lèi)型。titleTwo代表的是類(lèi)型可自定義,也就是值的部份除了定義的類(lèi)型,也可以是null或undefined,不過(guò)這屬性是需要的,而且你一定要給它一個(gè)值。好的,這有些太細(xì)部了,如果有用到再查手冊(cè)文檔就可以。
export type NavigationState = { index: number, routes: Array, };
上面的代碼可以看到,只要是聲明過(guò)的類(lèi)型(type),同樣可以拿來(lái)拿在其他類(lèi)型中套用,像這里的Array
剛已經(jīng)有說(shuō)過(guò)Flow工具有很大的原因是為了React與React Native所設(shè)計(jì),因?yàn)镕low本身就內(nèi)建對(duì)PropTypes的檢查功能,也可以正確檢查JSX語(yǔ)法,在這篇官方文檔中有說(shuō)明,而這在之后介紹React的文檔的例子中就可以看到。
安裝與使用Flow目前可以支持macOS、Linux(64位元)、Windows(64位元),你可以從以下的四種安裝方式選擇其中一種:
直接從Flow的發(fā)布頁(yè)面下載可運(yùn)行檔案,加到計(jì)算機(jī)中的PATH(路徑),讓flow指令可以在命令列窗口訪問(wèn)即可。
透過(guò)npm安裝即可,可以安裝在全局(global)或是各別項(xiàng)目中。下面為安裝在項(xiàng)目中的指令:
npm install --save-dev flow-bin
macOS中可以使用homebrew安裝:
brew update brew install flow
透過(guò)OCaml OPAM套裝管理程序打包與安裝,請(qǐng)見(jiàn)Flow的Github頁(yè)面。
Flow簡(jiǎn)單使用三步驟 第1步: 初始化項(xiàng)目在你的項(xiàng)目根目錄的用命令列工具輸入下面的指令,這將會(huì)創(chuàng)建一個(gè).flowconfig文檔,如果這文檔已經(jīng)存在就不需要再進(jìn)行初始化,這個(gè)設(shè)置檔一樣是可以加入自定義的設(shè)置值,請(qǐng)參考Advanced Configuration這里的說(shuō)明,目前有很多項(xiàng)目里面都已經(jīng)內(nèi)附這個(gè)設(shè)置檔,例如一些React的項(xiàng)目:
flow init第2步: 在代碼文檔中加入要作類(lèi)型檢查的注釋
一般都在代碼檔案的最上面一行加入,沒(méi)加Flow工具是不會(huì)進(jìn)行檢查的,有兩種格式都可以:
// @flow
或
/* @flow */第3步: 進(jìn)行檢查
目前支持Flow工具插件的代碼編輯工具很多,常見(jiàn)的Atom, Visual Studio Code(VSC), Sublime與WebStorm都有,當(dāng)有安裝搭配代碼編輯工具的插件時(shí),編輯工具會(huì)輔助顯示檢查的訊息。不過(guò)有時(shí)候會(huì)有點(diǎn)卡頓的要等一下,因?yàn)闄z查速度還不是那么快。
或是直接用下面的命令列指令來(lái)進(jìn)行檢查:
flow check
在Visual Studio Code中因?yàn)樗鼉?nèi)建TypeScript與JavaScript的檢查功能,如果要使用Flow工具來(lái)作類(lèi)型檢查,需要在用戶設(shè)置中,加上下面這行設(shè)置值以免沖突:
"javascript.validate.enable": false轉(zhuǎn)換(編譯)有Flow標(biāo)記的代碼
注: 有些腳手架就已經(jīng)裝好與設(shè)置好這個(gè)babel拓展插件,你不用再多安裝了。
在開(kāi)發(fā)的最后階段要將原本有使用Flow標(biāo)記,或是有類(lèi)型注釋的代碼,進(jìn)行清除或轉(zhuǎn)換。轉(zhuǎn)換的工作要使用babel編譯器,這也是目前較推薦的方式。
使用babel編譯器如果以命令列工具為主,可以使用下面的指令來(lái)安裝在全局中:
npm install -g babel-cli
再來(lái)加裝額外移除Flow標(biāo)記的npm套件babel-plugin-transform-flow-strip-types在你的項(xiàng)目中:
npm install --save-dev babel-plugin-transform-flow-strip-types
然后創(chuàng)建一個(gè).babelrc設(shè)置檔案,檔案內(nèi)容如下:
{ "plugins": [ "transform-flow-strip-types" ] }
完成設(shè)置后,之后babel在編譯時(shí)就會(huì)一并轉(zhuǎn)換Flow標(biāo)記。
下面的指令則是直接把src目錄的檔案編譯到dist目錄中:
babel src -d dist
當(dāng)然,babel的使用方式不是只有上面說(shuō)的這種命令列指令,你可以視項(xiàng)目的使用情況來(lái)進(jìn)行設(shè)置。
Flow支持的數(shù)據(jù)類(lèi)型Flow用起來(lái)是的確是簡(jiǎn)單,但里面的內(nèi)容很多,主要原因是是要看實(shí)際不同的使用情況作搭配。JavaScript里面的原始數(shù)據(jù)類(lèi)型都有支持,而在函數(shù)、對(duì)象與一些新的ES6中的類(lèi),在搭配使用時(shí)就會(huì)比較復(fù)雜,詳細(xì)的情況就請(qǐng)到官網(wǎng)文檔中觀看,以下只能提供一些簡(jiǎn)單的介紹說(shuō)明。
原始數(shù)據(jù)類(lèi)型Flow支持原始數(shù)據(jù)類(lèi)型,如下面的列表:
boolean
number
string
null
void
其中的void類(lèi)型,它就是JS中的undefined類(lèi)型。
這里可能要注意的是,在JS中undefined與null的值會(huì)相等但類(lèi)型不同,意思是作值相等比較時(shí),像(undefined == null)時(shí)會(huì)為true,有時(shí)候在一些運(yùn)行期間的檢查時(shí),可能會(huì)用值相等比較而不是嚴(yán)格的相等比較,來(lái)檢查這兩個(gè)類(lèi)型的值。
所有的類(lèi)型都可以使用垂直線符號(hào)(|)作為聯(lián)合使用(也就是 OR 的意思),例如string | number指的是兩種類(lèi)型其中一種都可使用,這是一種聯(lián)合的類(lèi)型,稱(chēng)為"聯(lián)合(Union)類(lèi)型"。
最特別的是可選的(Optional)類(lèi)型的設(shè)計(jì),可選類(lèi)型代表這個(gè)變量或常量的值有可能不存在,也就是允許它除了是某個(gè)類(lèi)型的值外,也可以是null或undefined值。要使用可選類(lèi)型,就是在類(lèi)型名稱(chēng)定義前加上問(wèn)號(hào)(?),例如?string這樣,下面是一個(gè)簡(jiǎn)單的例子:
let bar: ?string = null字面文字(literal)類(lèi)型
字面文字類(lèi)型指的是以真實(shí)值作為數(shù)據(jù)類(lèi)型,可用的值有三種,即數(shù)字、字符串或布爾值。字面文字類(lèi)型搭配聯(lián)合的類(lèi)型可以作為列舉(enums)來(lái)使用,例如以下的一個(gè)撲克牌的類(lèi)型例子:
type Suit = | "Diamonds" | "Clubs" | "Hearts" | "Spades"; type Rank = | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | "Jack" | "Queen" | "King" | "Ace"; type Card = { suit: Suit, rank: Rank, }
類(lèi)型別名注: type是Flow中定義類(lèi)型別名(Type Alias)的關(guān)鍵字,是一種預(yù)先聲明的類(lèi)型,這些聲明的標(biāo)記一樣只會(huì)在開(kāi)發(fā)階段中使用,最后編譯去除。
類(lèi)型別名(Type Alias)提供了可以預(yù)先定義與集中代碼中所需要的類(lèi)型,一個(gè)簡(jiǎn)單的例子如下:
type T = Arrayvar x: T = [] x["Hi"] = 2 //有Flow警告
類(lèi)型別名(Type Alias)也可以用于復(fù)雜的應(yīng)用情況,詳見(jiàn)Flow官網(wǎng)提供的Type Aliases內(nèi)容。
任何的數(shù)據(jù)類(lèi)型在某一些情況可能不需要定義的太過(guò)于嚴(yán)格,或是還在開(kāi)發(fā)中正在調(diào)試時(shí),有一種作為漸進(jìn)的改善代碼的類(lèi)型。
Flow提供了兩種特殊的類(lèi)型可以作為松散的數(shù)據(jù)類(lèi)型定義:
any: 相當(dāng)于不檢查。既是所有類(lèi)型的超集(supertype),也是所有類(lèi)型的子集(subtype)
mixed: 類(lèi)似于any是所有類(lèi)型的超集(supertype),但不同于any的是,它不是所有類(lèi)型的子集(subtype)
mixed是一個(gè)特別的類(lèi)型,中文是混合的意思,mixed算是any的"啰嗦"進(jìn)化類(lèi)型。mixed用在函數(shù)的輸入(傳參)與輸出(返回)時(shí),會(huì)有不一樣的狀態(tài),例如以下的例子會(huì)出現(xiàn)警告:
function foo(x: mixed): string { return x + "10" } foo("Hello!") foo(1)
會(huì)出現(xiàn)警告消息如下:
[flow] mixed (Cannot be added to string)
這原因是雖然輸入時(shí)可以用mixed,但Flow會(huì)認(rèn)為函數(shù)中x的值不見(jiàn)得可以與string類(lèi)型作相加,所以會(huì)請(qǐng)求你要在函數(shù)中的代碼,要加入檢查對(duì)傳入類(lèi)型在運(yùn)行期間的類(lèi)型檢查代碼,例如像下面修改過(guò)才能過(guò)關(guān):
function foo(x: mixed): string { if (typeof x === "number" || typeof x === "string") { return x + "10" } throw new Error("Invalid x type") } foo("Hello!") foo(1)
mixed雖然"啰嗦",但它是用來(lái)漸進(jìn)替換any使用的,有時(shí)候往往開(kāi)發(fā)者健忘或偷懶沒(méi)作傳入值在運(yùn)行期間的類(lèi)型檢查,結(jié)果后面要花更多的時(shí)間才能找出錯(cuò)誤點(diǎn),這個(gè)類(lèi)型的設(shè)計(jì)大概是為了提早預(yù)防這樣的情況。
復(fù)合式的數(shù)據(jù)類(lèi)型 數(shù)組(Array)注: 從上面的例子可以看到Flow除了對(duì)類(lèi)型會(huì)作檢查外,它也會(huì)請(qǐng)求對(duì)某些類(lèi)型需要有動(dòng)態(tài)的檢查。在官方的文件可以參考Dynamic Type Tests這個(gè)章節(jié)。
數(shù)組類(lèi)型使用的是Array
對(duì)象類(lèi)型會(huì)比較麻煩,主要原因是在JavaScript中所有的數(shù)據(jù)類(lèi)型大概都可以算是對(duì)象,就算是基礎(chǔ)數(shù)據(jù)類(lèi)型也有對(duì)應(yīng)的包裝對(duì)象,再加上有個(gè)異常的null類(lèi)型的typeof返回值也是對(duì)象。
對(duì)象類(lèi)型在Flow中的使用,基本上要分作兩大部份來(lái)說(shuō)明。
第一種是單指Object這個(gè)類(lèi)型,F(xiàn)low會(huì)判斷所有的基礎(chǔ)數(shù)據(jù)類(lèi)不是屬于這個(gè)類(lèi)型的,以下的例子全部都會(huì)有警告:
// 以下都有Flow警告 (0: Object); ("": Object); (true: Object); (null: Object); (undefined: Object);
其他的復(fù)合式數(shù)據(jù)類(lèi)型,除了數(shù)組之外,都會(huì)認(rèn)為是對(duì)象類(lèi)型。如下面的例子:
({foo: "foo"}: Object); (function() {}: Object); (class {}: Object); ([]: Object); // Flow不認(rèn)為數(shù)組是屬于對(duì)象
注意: 上面有兩個(gè)特例,typeof null與typeof []都是返回"object"。也就是說(shuō)在JS的標(biāo)準(zhǔn)定義中,null與數(shù)組用typeof檢測(cè)都會(huì)返回對(duì)象類(lèi)型。所以,F(xiàn)low工具的檢查會(huì)與JS預(yù)設(shè)并不相同,這一點(diǎn)要注意。
注: typeof在Flow中有一些另外的用途,詳見(jiàn)Typeof的說(shuō)明。
第二種方式是要定義出完整的對(duì)象的字面文字結(jié)構(gòu),像{ x1: T1; x2: T2; x3: T3;}的語(yǔ)法,用這個(gè)結(jié)構(gòu)來(lái)檢查,以下為例子:
let object: {foo: string, bar: number} = {foo: "foo", bar: 0}; object.foo = 111; //Flow警告 object.bar = "111"; //Flow警告函數(shù)(Function)
上面已經(jīng)有看到,函數(shù)也屬于對(duì)象(Object)類(lèi)型,當(dāng)然也有自己的Function類(lèi)型,函數(shù)的類(lèi)型也可以從兩大部份來(lái)看。
第一是單指Function這個(gè)類(lèi)型,可以用來(lái)定義變量或常量的類(lèi)型。如下面的代碼例子:
var anyFunction: Function = () => {};
第二指的是函數(shù)中的用法,上面已經(jīng)有看到函數(shù)的輸出(返回值)與輸入(傳參)的用法例子。例如以下的例子:
function foo(x: number): number { return x + 10; }
因?yàn)楹瘮?shù)有很多種不同的使用情況,實(shí)際上可能會(huì)復(fù)雜很多,F(xiàn)low工具可以支持目前最新的arrow functions、async functions與generator functions,詳見(jiàn)官方的這篇Functions的說(shuō)明。
類(lèi)(Class)類(lèi)是ES6(ES2015)中新式的特性,類(lèi)目前仍然只是原型的語(yǔ)法糖,類(lèi)本身也屬于一種對(duì)象(Object)類(lèi)型。類(lèi)的使用情況也可能會(huì)復(fù)雜,尤其是涉及多型與實(shí)例的情況,詳見(jiàn)Flow網(wǎng)站提供的Classes內(nèi)容。
Flow的現(xiàn)在與未來(lái)的發(fā)展Flow在最近的博客中說(shuō)明引入了flow-typed的函數(shù)庫(kù)定義檔("libdefs"),在這個(gè)Github存儲(chǔ)庫(kù)中將統(tǒng)一存放所有來(lái)自社群提供的函數(shù)庫(kù)定義檔案。這是一種可以讓現(xiàn)有的函數(shù)庫(kù)與框架,預(yù)先寫(xiě)出里面使用的類(lèi)型定義。讓項(xiàng)目里面有使用Flow工具與這些函數(shù)庫(kù),就可以直接使用這些定義檔,以此結(jié)合現(xiàn)有的函數(shù)庫(kù)與框架來(lái)使用。這個(gè)作法是參考TypeScript的DefinitelyTyped方式。因?yàn)檫@還是很新的消息(2016.10),目前加入的函數(shù)庫(kù)還沒(méi)有太多,不過(guò)React周邊的一些函數(shù)庫(kù)或組件都已經(jīng)開(kāi)始加入,其他常用的像underscore、backbone或lodash也已經(jīng)有人在提交或維護(hù)。
Flow另一個(gè)發(fā)展會(huì)是在開(kāi)發(fā)工具的自動(dòng)完成功能的改進(jìn),因?yàn)槿绻呀?jīng)能在撰寫(xiě)代碼時(shí),就知道變量或常量的類(lèi)型(靜態(tài)類(lèi)型),那么在自動(dòng)完成功能中就可以更準(zhǔn)確地給出可用的屬性或方法。這一個(gè)功能在Facebook自家的Nuclide開(kāi)發(fā)工具的Flow說(shuō)明頁(yè)中就有看到。Nuclide是基于Atom開(kāi)發(fā)工具之上的工具,計(jì)算機(jī)硬件如果不夠力是跑不動(dòng)的,而且它穩(wěn)定性與運(yùn)行速度都還需要再努力。這大概是未來(lái)可見(jiàn)到的一些新趨向。
結(jié)論本文簡(jiǎn)單的說(shuō)明了Flow工具的功能介紹,以及其中的一些簡(jiǎn)要的內(nèi)容等等。相信看過(guò)后你已經(jīng)對(duì)這個(gè)Flow工具有一些認(rèn)識(shí),以我個(gè)人學(xué)過(guò)TypeScript的經(jīng)驗(yàn),相較于TypeScript的學(xué)習(xí)曲線,F(xiàn)low大概是等于不用學(xué)。Flow雖然是一個(gè)很新的工具,但相當(dāng)?shù)挠杏?,建議每個(gè)JavaScript開(kāi)發(fā)者都可以試試,一開(kāi)始不用學(xué)太多,大概這篇文檔看完就可以開(kāi)始用了。復(fù)雜的地方就再查找官方的文件即可。
對(duì)于每個(gè)正在使用JS開(kāi)發(fā)稍具規(guī)模化的應(yīng)用,或是開(kāi)發(fā)開(kāi)源碼的函數(shù)庫(kù)或框架的團(tuán)隊(duì)來(lái)說(shuō),讓JS具有靜態(tài)類(lèi)型特性,是一個(gè)很重要而且必要的決定。以我的觀察,在網(wǎng)絡(luò)上一直有很多的超集語(yǔ)言(例如TypeScript)的愛(ài)好者,會(huì)提出要全面改用TypeScript(或其他超集語(yǔ)言)的聲音,例如Vue.js在很早之前就有討論是不是要全面采用TypeScript的聲音。后來(lái)Vue.js只有提交TypeScript的DefinitelyTyped文檔,但在2.0中則采行了Flow工具。在這篇Vue作者于知乎上發(fā)表的: Vue 2.0 為什么選用 Flow 進(jìn)行靜態(tài)代碼檢查而不是直接使用 TypeScript?的內(nèi)容中,你可以看到為何選擇Flow的理由,這可能也是整個(gè)開(kāi)發(fā)團(tuán)隊(duì)所認(rèn)同的最后結(jié)果。作者回答的文中可以總結(jié)下面這句話:
全部換 TS(TypeScript) 成本過(guò)高,短期內(nèi)并不現(xiàn)實(shí)。 相比之下 Flow 對(duì)于已有的 ES2015 代碼的遷入/遷出成本都非常低 … 萬(wàn)一哪天不想用 Flow 了,轉(zhuǎn)一下,就得到符合規(guī)范的 ES。
總之,F(xiàn)low提供了另一個(gè)選擇,要用什么工具就看聰明的你如何選擇了。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/81171.html
摘要:本文主要介紹了解決作為弱類(lèi)型語(yǔ)言沒(méi)有類(lèi)型檢查痛點(diǎn)的靜態(tài)類(lèi)型檢查工具,并且介紹了在中使用的方法,最后介紹了一些常用的語(yǔ)法。 本文主要介紹了解決JS作為弱類(lèi)型語(yǔ)言沒(méi)有類(lèi)型檢查痛點(diǎn)的靜態(tài)類(lèi)型檢查工具 Flow ,并且介紹了在WebStorm中使用Flow的方法,最后介紹了一些常用的Flow語(yǔ)法。 1. 簡(jiǎn)介 JS作為一種腳本語(yǔ)言是沒(méi)有類(lèi)型檢測(cè)的,這個(gè)特點(diǎn)有時(shí)候用著很方便,但在一個(gè)較大的項(xiàng)目中...
摘要:擴(kuò)展靜態(tài)類(lèi)型檢查語(yǔ)言與系列等語(yǔ)言有一點(diǎn)很大的不同,就是語(yǔ)言是弱類(lèi)型語(yǔ)言。但其實(shí)很多開(kāi)發(fā)人員還是比較喜歡用來(lái)開(kāi)發(fā)項(xiàng)目,所以開(kāi)發(fā)出來(lái)幫助語(yǔ)言擴(kuò)展靜態(tài)類(lèi)型檢查功能,規(guī)避上面提到的問(wèn)題。 js 擴(kuò)展:靜態(tài)類(lèi)型檢查(facebook flow) js 語(yǔ)言與 java、C 系列等語(yǔ)言有一點(diǎn)很大的不同,就是 js 語(yǔ)言是弱類(lèi)型語(yǔ)言。js 語(yǔ)言的這個(gè)特性可能讓大家覺(jué)得 js 很自由,沒(méi)有強(qiáng)制性的約束...
摘要:一是一種弱類(lèi)型動(dòng)態(tài)類(lèi)型檢查的語(yǔ)言。動(dòng)態(tài)類(lèi)型與靜態(tài)類(lèi)型的核心區(qū)別動(dòng)態(tài)類(lèi)型的類(lèi)型檢查是是在代碼運(yùn)行的時(shí)候進(jìn)行的,靜態(tài)類(lèi)型的類(lèi)型檢查則是在編譯時(shí)進(jìn)行。 一、js是一種弱類(lèi)型、動(dòng)態(tài)類(lèi)型檢查的語(yǔ)言。 弱類(lèi)型:在定義變量時(shí),可以為變量定義復(fù)制任何數(shù)據(jù),變量的數(shù)據(jù)類(lèi)型不是固定死的,這樣的類(lèi)型叫做弱類(lèi)型。 var a = 10; a = abc; a = []; a = function() {}...
摘要:原文鏈接翻譯于今天我們興奮的發(fā)布了的嘗鮮版,一個(gè)新的靜態(tài)類(lèi)型檢查器。為添加了靜態(tài)類(lèi)型檢查,以提高開(kāi)發(fā)效率和代碼質(zhì)量。這最終形成一個(gè)高度并行增量式的檢查架構(gòu),類(lèi)似。知道縮小類(lèi)型范圍時(shí)做動(dòng)態(tài)檢查的影響。 原文鏈接:https://code.facebook.com/posts/1505962329687926/flow-a-new-static-type-checker-for-java...
閱讀 3301·2023-04-26 02:09
閱讀 2608·2021-11-24 09:39
閱讀 3296·2021-11-16 11:52
閱讀 3628·2021-10-26 09:50
閱讀 2785·2021-10-08 10:05
閱讀 2472·2021-09-22 15:25
閱讀 3314·2019-08-30 13:14
閱讀 928·2019-08-29 17:06