類型和表達式
在 JavaScript 中有許多類型的值:數字、字串、布林值、函式、物件等。
11234 as number;2"hi" as string;3true as boolean;4[1, 2] as Array<number>;5({prop: "value"}) as {prop: string};6(function func(s: string) {}) as string => void;
這些值可以用於許多不同的方式
11 + 2;2"foo" + "bar";3!true;4[1, 2].push(3);5const obj = {prop: "s"};6let value = obj.prop;7obj.prop = "value";8function func(s: string) {}9func("value");
所有這些不同的表達式都會建立一個新類型,這是值類型和對其執行的運算結果。
1let num: number = 1 + 2;2let str: string = "foo" + "bar";
在 Flow 中,每個值和表達式都有類型。
靜態找出類型
Flow 需要一種方法來找出每個表達式的類型。但它不能只執行你的程式碼來找出,如果它這樣做,它會受到你的程式碼有任何問題的影響。例如,如果你建立一個無限迴圈,Flow 會永遠等待它完成。
相反地,Flow 需要能夠在不執行它的情況下分析值來找出類型(靜態分析)。它會處理每個已知類型,並開始找出它們周圍的所有表達式所產生的結果。
例如,為了找出下列表達式的結果,Flow 需要先找出其值為何。
val1 + val2;
如果值是數字,則表達式會產生數字。如果值是字串,則表達式會產生字串。這裡有許多不同的可能性,所以 Flow 必須找出值為何。
如果 Flow 無法找出每個值的精確類型,Flow 必須找出每個可能的值,並檢查確保其周圍的程式碼仍可與所有可能的類型一起使用。
健全性和完整性
當您執行程式碼時,單一表達式只會使用有限制的數值集執行。但 Flow 仍會檢查每個可能的值。以這種方式,Flow 會檢查過多的項目,或過度近似有效的程式碼。
透過檢查每個可能的值,Flow 可能會發現執行程式碼時實際上不會發生的錯誤。Flow 執行此操作是為了「健全」。
在類型系統中,健全性是指類型檢查器在執行階段發現可能發生的每個錯誤的能力。這必須付出代價,有時會發現執行階段實際上不會發生的錯誤。
另一方面,完整性是指類型檢查器只發現執行階段會發生的錯誤的能力。這必須付出代價,有時會遺漏執行階段會發生的錯誤。
在理想的世界中,每個類型檢查器都會健全且完整,以便在執行階段發現每個會發生的錯誤。
Flow 嘗試盡可能健全且完整。但由於 JavaScript 並非以類型系統為基礎設計,因此 Flow 有時必須做出取捨。當發生這種情況時,Flow 傾向於優先健全性而非完整性,確保程式碼沒有任何錯誤。
只要 Flow 不會太過吵雜,也不會妨礙您的生產力,健全性就沒問題。有時當健全性會造成太多阻礙時,Flow 會優先考慮完整性。Flow 這樣做的情況只有少數幾種。
其他類型系統會優先考慮完整性,只回報真實的錯誤,而可能遺漏錯誤。單元/整合測試是這種方法的極端形式。這通常必須付出代價,遺漏最難發現的錯誤,讓開發人員負責處理這部分。