原文連接:https://code.facebook.com/posts/1505962329687926/flow-a-new-static-type-checker-for-javascript/javascript
Avik Chaudhuri Basil Hosmer Gabriel Leviphp
caisijie 翻譯於 2015/12/21java
今天咱們興奮的發佈了Flow的嚐鮮版,一個新的Javascript靜態類型檢查器。Flow爲Javascript添加了靜態類型檢查,以提升開發效率和代碼質量。更明確的說,靜態類型檢查提供的好處像早期錯誤檢查,幫助你發現一些只有在運行時才能發現的錯誤,以及代碼智能感知,它會幫助代碼維護,查找,重構和優化。算法
咱們設計Flow的全部功能構建在現有Javascript規範之上。由於Flow主動地在後臺工做,因此額外的編譯開銷很小。Flow並不要求開發者如何編寫代碼 —— 她用一套複雜的算法分析你熟悉的代碼風格。編程
Flow仍然在初期階段,可是咱們已經在Facebook使用了。咱們但願你在本身的項目中愉快的使用,期待你的反饋。能夠訪問flowtype.org快速開始。數組
Facebook超愛Javascript;它快,表達性好,並且處處運行,是構建產品的極佳語言。同時,由於沒有靜態類型讓開發者困擾。Bug難以發現(好比,崩潰的緣由隱藏很深),代碼維護猶如噩夢(好比,在不知道全部依賴的狀況下進行重構風險很大)。Flow改進了速度和效率促進了開發者在使用Javascript的生成效率。安全
在Javascript之上添加一層靜態系統並不簡單。Javascript的積木(building block)表現力極高,一個簡單的類型系統並不能精確組合出應有的語義。爲了支持不一樣的Javascript編程範式和習慣,Flow引入了相似數據流(data-flow)和控制流(control-flow)這類一般用於編譯時提取語義的分析技術。而後用提取的信息,加上先進的類型原理來作類型推斷。固然,僅有一個強力的靜態類型分析還不夠 —— Javascript代碼庫會很大,這要求類型檢查必須閃電般快速,才能不打斷開發者編輯-運行的流程。Flow按模塊執行分析,全部的類型都限制在模塊邊界之內。這最終造成一個高度並行、增量式的檢查架構,相似Hack。這使得類型檢查響應快速,即便是百萬行級別代碼。服務器
Flow的類型檢查是選擇性的 —— 你不須要一次性執行檢查全部。然而,Flow背後的設計基於假定大多數Javascript的代碼類型是隱式靜態類型;雖然類型可能不會處處在代碼中出現,它們是以一種能夠按照代碼正確性推理出來的形式存在於開發者的思路中。一旦可能,Flow就去推斷這些類型,意味着它能夠不須要改動代碼就能發現類型錯誤。另外一發面,一些如存在於框架中的Javascript代碼,大量使用了反射使得靜態類型推斷很是困難。對於這種自然動態的代碼,類型檢查就會錯漏百出,所以Flow提供對此類代碼添加信任並繼續。這種設計在Facebook內部被大量的Javascript代碼庫所驗證:大多數代碼沒有經過隱式靜態類型檢查條目,這些條目讓開發者能夠不用添加註釋就能檢查代碼類型錯誤。架構
這使得Flow從根本上區別於其餘Javascript的類型系統(如TypeScript),經過弱化的假設大多數JavaScript代碼是動態輸入的,並由開發者本身表達哪些代碼應該是靜態類型。一般來看,這類設計會致使檢查覆蓋率下降:更少的類型錯誤被檢測到,工具不夠高效。然而對於某些狀況下是合理的,通常這種設計若是沒有經過大量額外的努力就沒法對實際開發提供足夠多的幫助。儘管如此,Flow讓你能夠簡單就得到這種弱化的類型檢查,對於現有代碼很是有用。框架
爲了解釋這種區別,請看下面的例子:
function onlyWorksOnNumbers(x) { return x * 10; } onlyWorksOnNumbers(‘Hello, world!’);
Flow可以發現這個錯誤(嘗試把數字和字符串相乘),然而另外一種更加保守的分析須要顯式的標註x
的類型。在這個玩具般的例子裏面並不以爲費力,可是在巨型代碼庫裏面幾乎無人去作。Flow能夠不用添加註釋就能發現這個錯誤 —— 固然前提是開發者想這樣作。
Flow的類型系統實現了許多指望中的功能。支持標準基本類型(number
, string
,boolean
),類型之間的隱式轉換在除一些特殊情形外是被禁止的。結構類型,如函數、對象和數組也被支持。類型能夠是多態的。
也許你會感到意外,Flow沒有把null
和undefined
當成是上述類型中的任何一種。這兩種類型會有多種可能,使用這些類型必須在合理檢查的保護之上。其它組合類型(如 string | number
)也被支持,這種用法一樣須要確保安全。Flow知道縮小類型範圍時作動態檢查的影響。
讓咱們用一個例子來描述處理null
值。下面的程序老是在運行時崩潰,可是通常的類型系統會認爲它沒有問題:
function length(x) { return x.length; } var total = length('Hello') + length(null);
Flow會在編譯時期發現這個錯誤,並指出x
能夠是null(length
屬性不該該被訪問)。另外,Flow瞭解這個程序的控制流,因此簡單修改就能讓這個程序類型正確:
function length(x) { if (x !== null) { return x.length; } else { return 0; } } var total = length('Hello') + length(null);
Flow還了解JavaScript複雜的對象模型:構造器,方法,原型和它們動態擴展以及綁定。已經試驗性去支持類型的複雜操做如:綁定對象,抽取keys等等。咱們但願將來這些功能使得讓爲框架指定具體類型成爲可能。
類型錯誤一般報告爲定義和實際值不兼容:好比函數調用的參數不足,對象中不包含要訪問的屬性,或者把字符串當成數字使用。
最後,Flow支持動態類型(any
),這種類型能夠繞過類型系統檢查:好比可用any
表示靜態分析沒法準確判斷而報錯的location(一般使用反射的狀況)。另外Flow在弱模式下遇到上述類型且沒有註釋類型的話,會自動假定爲any
。
更多關於類型系統能夠查看 documentation.
爲了拓展,Flow根據模塊和其它模塊的依賴關係以及其它模塊提供的類型接口,單獨對每一個模塊進行檢查。要生成類型接口,Flow可能須要在模塊邊界上進行註釋。
Flow在一個後臺運行的持久化服務器上,維護着整個代碼庫的語義信息,一開始Flow會對整個代碼作一次分析,而後當一系列文件改動的時候(多是單個文件改動或者在切換分支的時候),服務器會增量式更新改動文件以及因爲類型關聯的其它相關文件的語義信息。這樣,當開發者試圖獲取類型錯誤時,它們已經在服務器上了,相應幾乎是當即的。這種服務器架構與Hack構建在同一種技術之上。
Flow致力於支持最新的JavaScript標準。目前已經支持各類ES6特性如destructuring, classes, extended objects, optional function parameters,以及核心API擴展(好比Map, Set, Promise, 和 new methods on Object, Array, 和 Math)。其它特性(尤爲是模塊)正在開發中。Flow支持CommonJS / Node.js 規範的模塊。
var Hello = React.createClass ({ render: function() { return <div>Hello {this.props.name}</div>; } });
若是你在JSX上使用的class名字有錯誤,Flow會發現這個問題:React.render(, ...);
並且,若是你在React class裏面使用了React.PropTypes規範,你能夠對JSX上的attributes作靜態類型檢查:
var Hello = React.createClass ({ propTypes: { name: React.PropTypes.string.isRequired } ... });
Flow就會發現 <Hello/>
缺乏屬性的錯誤,或者<Hello name={42}/>
屬性類型的錯誤。
更多的關於支持React的細節能夠在文檔中找到。
Flow代碼大部分用OCaml實現。代碼庫在活躍更新而且會在將來幾個月快速進化。除了在Facebook範圍內的數據代碼庫中運行外,咱們但願Flow的分析引擎能用於構建相似的,不管是JavaScript或者其餘的語言工具。請讓咱們知道你是否想加入!
想了解更多關於Flow,下載它試試吧,查看 flowtype.org。