Flow是facebook出品的JavaScript靜態類型檢查工具。 因爲JavaScript是動態類型語言,它的靈活性也會形成一些代碼隱患,使用Flow能夠在編譯期儘早發現由類型錯誤引發的bug,這種方式很是有利於大型項目源碼的開發和維護。javascript
npm install --g flow-bin
java
建立一個項目文件夾./demo
進入項目文件夾。git
npm init -y
建立package.json文件,在文件中的scripts中添加:github
"scripts": {
"flow": "flow"
}
複製代碼
這就完成了而後開始正式使用。typescript
一、經過npm run flow init
命令會在項目文件夾的根目錄建立一個.flowconfig
文件。npm
二、經過npm run flow check
命令能夠在你的項目根目錄以及任何子目錄文件夾下進行專門的類型檢查,可是,這並非最高效的使用方式,由於每次Flow都會從新檢查整個項目的全部文件,開發過程當中,推薦啓動Flow服務。json
三、經過npm run flow
命令啓動Flow服務,Flow服務的工做方式是增量檢查也就是說它只檢查變化的部分,首次運行該命令時,服務啓動而且顯示最初類型檢查結果,這保證了Flow更高效的增量式工做流,而後接下來每次想要知道檢測結果,只要輸入flow
命令便可。開發結束以後,輸入npm run flow stop
中止服務。數組
Flow的類型檢查是可選的,並不須要一次性檢查全部代碼。你能夠選擇你想要檢查的文件,只要在對應的JavaScript文件最前面加上帶有@flow
標識的註釋便可:瀏覽器
/*@flow*/
function foo(a) {
return a;
}
fn(1);
複製代碼
一般,類型檢查分爲如下兩種方式:babel
一、經過註釋:事先註釋好咱們期待的類型,Flow就會基於這些註釋來評估
二、經過代碼推斷:經過變量的使用上下文來推斷出變量類型,而後根據這些推斷來檢查類型
第一種方式,咱們須要額外編寫只在開發階段起做用的代碼,最後在代碼編譯打包的階段被剔除。顯然,這種額外添加類型註釋的方式增長了工做量。
第二種方式,不須要任何代碼修改便可進行類型檢查,最小化開發者的工做量。它不會強制你改變開發習慣,由於它會自動推斷出變量的類型。這就是所謂的類型推斷,Flow最重要的特性之一。
/*@flow*/
function foo(x) {
return x.split(' ');
}
foo(34);
複製代碼
當你在終端運行npm run flow
命令的時候,上述代碼會報錯,由於函數foo()
的期待參數是字符串,而咱們輸入了數字,錯誤信息相似以下:
上述信息清楚地指出了出錯位置和錯誤緣由。咱們只要將參數變成字符串,便可修正錯誤,以下所示:
/*@flow*/
function foo(x) {
return x.split(' ');
}
foo("Hello World");
複製代碼
split()
方法只適用於string
類型的變量,因此x
應該是string
,這就是類型推斷。
Flow處理null
。它不會忽略null
,這樣能夠防止,由於給變量傳了null
而致使程序崩潰的錯誤。
/*@flow*/
function stringLength(str) {
return str.length;
}
var length = stringLength(null);
複製代碼
Flow會報錯。爲了防止出錯,咱們須要單獨處理null
。
/*@flow*/
function stringLength (str) {
if (str !== null) {
return str.length;
}
return 0;
}
var length = stringLength(null);
複製代碼
代碼中咱們引入對null
的檢查,確保代碼能在任何狀況下都正常且正確運行。上述代碼能夠經過Flow的類型檢查。
類型推斷是Flow最有用的特性之一,不須要編寫類型註釋就能獲取有用的反饋。但在某些特定的場景下,添加類型註釋能夠提供更好更明確的檢查依據。
/*@flow*/
function foo(x, y){
return x + y;
}
foo('Hello', 18);
複製代碼
Flow檢查上述代碼時檢查不出任何錯誤,由於+
便可以用在字符串上,也能夠用在數字上,咱們並無明確指出foo()
的參數必須爲數字。
在這種狀況下,咱們能夠藉助類型註釋來指明指望的類型。類型註釋是以冒號:
開頭,能夠在函數參數,返回值,變量聲明中使用,若是咱們在上段代碼中添加類型註釋,就會變成以下:
/*@flow*/
function foo(x : number, y : number) : number {
return x + y;
}
foo('Hello', 18);
複製代碼
第一個和第二個number是x和y兩個形參須要接收number類型的值,第三個number是foo()函數須要返回一個number的值
如今Flow就能檢查出錯誤,由於函數參數的期待類型爲數字,而咱們提供了字符串,錯誤信息:
若是傳入的參數是數字,就不會有錯誤。
/*@flow*/
function add(x : number, y : number) : number {
return x + y;
}
add(3, 4);
複製代碼
上述代碼展現了變量類型註釋以及函數類型註釋。函數add()
的參數,以及函數的返回值,期待類型爲數字。若是傳入其餘類型參數,Flow就會檢測到錯誤。
/*@flow*/
var foo : Array<number> = [1,2,3];
複製代碼
數組類型註釋的格式是Array<T>
,T
表示數組中每項的數據類型。在上述代碼中,foo
是每項均爲數字的數組。
下面展現了類和對象的類型註釋模型。惟一須要注意的是,能夠在兩個類型之間使用或邏輯,用|
來間隔。變量bar1
添加了必須爲Bar
類的類型註釋。
/*@flow*/
class Bar {
x: string;
y: string | number;
constructor(x, y) {
this.x = x;
this.y = y;
}
}
var bar1: Bar = new Bar("hello", 4);
複製代碼
對象的類型註釋,跟類的類型註釋很像,指定對象屬性的類型。
/*@flow*/
var obj: { a: string, b: number, c: Array<string>, d: Bar } = {
a: "hello",
b: 42,
c: ["hello", "world"],
d: new Bar("hello", 3)
}
複製代碼
若想任意類型T
能夠爲null
或者undefined
,只需相似以下寫成?T
的格式便可。
/*@flow*/
var foo: ?string = null;
複製代碼
此時,foo
能夠爲字符串,也能夠爲null
。
咱們常常須要引入第三方庫,Flow檢查時就會拋出錯誤。但這並非咱們期待的錯誤。
慶幸的是,咱們不須要修改庫源碼去防止這些報錯。咱們只需建立一個庫定義(libdef)。libdef是包含第三方庫聲明的JS文件簡稱。
觀察下面的例子:
/* @flow */
var users = [
{ name: 'John', designation: 'developer' },
{ name: 'Doe', designation: 'designer' }
];
function getDeveloper() {
return _.findWhere(users, {designation: 'developer'});
}
複製代碼
會報錯:
因爲Flow並不認識$
,因此會報錯。要解決這個問題,咱們須要引入jQuery的庫定義。
經過npm install -g flow-typed
安裝flow-typed倉庫,它包含了衆多流行的第三方庫的libdef。只需在項目根目錄下建立一個名爲flow-typed
的文件夾,而且下載相關的定義文件便可。
安裝成功以後, 運行flow-typed install
來檢查package.json
文件,而且下載全部項目中用到的第三方庫的libdef。 等待的時間有點久,等下載完後,再npm run flow
,就會發現沒有錯誤了。
若是你用的庫並不在flow-typed倉庫,你能夠建立你本身的libdef,感興趣能夠查看自定義libdef;
因爲額外添加的類型註釋不是正確的JavaScript語法,打包編譯的時候須要在源碼中剔除。能夠經過flow-remove-types來剔除,或者若是你已經用Babel來轉譯JS,你可使用Babel preset來移除。咱們只討論第一種方法。
首先須要安裝flow-remove-types做爲項目依賴庫:npm install --save-dev flow-remove-types
而後在package.json
文件中添加另外一個script
入口:
"scripts": {
"flow": "flow",
"build": "flow-remove-types src/ -d dist/"
}
複製代碼
運行npm run build
將剔除src
文件夾下的全部類型註釋,在dist
文件夾中保存編譯後的版本。編譯後的文件就是普通的能運行於瀏覽器的JavaScript文件。
//編譯前,/* @flow */記得寫。
/* @flow */
function fn1(x :number) {
return x;
}
fn1(1)
複製代碼
//編譯後
/* */
function fn1(x ) {
return x;
}
fn1(1)
複製代碼
本文討論了Flow各類各樣的類型檢查特性,展現了Flow如何幫助咱們捕獲錯誤提升代碼質量。咱們也看到了如何用可選的方式去逐個檢查JS文件,如何作類型推斷。
本人的博客 本人的github 本人的郵箱:scarf666@163.com
本文章配合TypeScript食用更佳