聯(lián)合類型
有時点楼,創(chuàng)建一個其他類型之一的類型很有用。例如白对,您可能希望編寫一個接受一組原始值類型的函數(shù)掠廓。對于此Flow支持聯(lián)合類型。
// @flow
function toStringPrimitives(value: number | boolean | string) {
return String(value);
}
toStringPrimitives(1); // Works!
toStringPrimitives(true); // Works!
toStringPrimitives('three'); // Works!
// $ExpectError
toStringPrimitives({ prop: 'val' }); // Error!
// $ExpectError
toStringPrimitives([1, 2, 3, 4, 5]); // Error!
語法
聯(lián)合類型是任意數(shù)量的類型甩恼,由 | 連接蟀瞧。
Type1 | Type2 | ... | TypeN
您還可以添加一個引導(dǎo)豎線,這在將聯(lián)合類型拆分到多行時非常有用条摸。
type Foo =
| Type1
| Type2
| ...
| TypeN
聯(lián)合類型的每個成員可以是任何類型悦污,甚至可以是另一個聯(lián)合類型。
type Numbers = 1 | 2;
type Colors = 'red' | 'blue'
type Fish = Numbers | Colors;
聯(lián)合類型需要一個輸入钉蒲,但全部輸出
在調(diào)用接受聯(lián)合類型的函數(shù)時切端,必須傳入其中一種類型。但是在函數(shù)內(nèi)部顷啼,我們需要處理所有可能的類型踏枣。
讓我們重寫函數(shù)昌屉,分別處理每種類型
// @flow
// $ExpectError
function toStringPrimitives(value: number | boolean | string): string { // Error!
if (typeof value === 'number') {
return String(value);
} else if (typeof value === 'boolean') {
return String(value);
}
}
您會注意到,如果我們不處理值的每種可能類型茵瀑,F(xiàn)low將給我們一個錯誤间驮。
聯(lián)合 & 細化
當(dāng)您有一個聯(lián)合類型的值時,將其分開并分別處理每個單獨的類型通常是很有用的马昨。使用流中的聯(lián)合類型竞帽,您可以將值“細化”為單個類型。
// @flow
function toStringPrimitives(value: number | boolean | string) {
if (typeof value === 'number') {
return value.toLocaleString([], { maximumSignificantDigits: 3 }); // Works!
}
// ...
}
通過檢查值的類型并測試它是否是一個數(shù)字鸿捧,F(xiàn)low知道在該塊內(nèi)部它只是一個數(shù)字屹篓。然后,我們可以編寫代碼笛谦,將我們的值視為該塊內(nèi)的一個數(shù)字抱虐。
不相交聯(lián)合
在flow中有一種特殊類型的聯(lián)合,稱為“不相交聯(lián)合”饥脑,可用于改進恳邀。這些不相交的聯(lián)合由任意數(shù)量的對象類型組成,每個對象類型都由一個屬性標(biāo)記灶轰。
例如谣沸,假設(shè)我們有一個函數(shù),用于在發(fā)送請求后處理來自服務(wù)器的響應(yīng)笋颤。當(dāng)請求成功時乳附,我們將返回一個具有成功屬性的對象,該屬性是true和我們已經(jīng)更新的值伴澄。
{ success: true, value: false };
當(dāng)請求失敗時赋除,我們將獲得一個成功設(shè)置為false的對象和一個描述錯誤的Error屬性。
{ success: false, error: 'Bad request' };
我們可以嘗試用一個對象類型來表示這兩個對象非凌。但是举农,我們很快就會遇到這樣的問題:我們根據(jù)Success屬性知道一個屬性存在,但Flow不知道敞嗡。
// @flow
type Response = {
success: boolean,
value?: boolean,
error?: string
};
function handleResponse(response: Response) {
if (response.success) {
// $ExpectError
var value: boolean = response.value; // Error!
} else {
// $ExpectError
var error: string = response.error; // Error!
}
}
試圖把這兩種不同的類型合并成一種颁糟,只會給我們帶來麻煩。
相反喉悴,如果我們創(chuàng)建這兩種對象類型的聯(lián)合類型棱貌,F(xiàn)low將能夠根據(jù)Success屬性知道我們使用的是哪個對象。
// @flow
type Success = { success: true, value: boolean };
type Failed = { success: false, error: string };
type Response = Success | Failed;
function handleResponse(response: Response) {
if (response.success) {
var value: boolean = response.value; // Works!
} else {
var error: string = response.error; // Works!
}
}
精確的不相交聯(lián)合
不相交的聯(lián)合要求您使用單個屬性來區(qū)分每種對象類型箕肃。不能通過不同的屬性區(qū)分兩個不同的對象婚脱。
// @flow
type Success = { success: true, value: boolean };
type Failed = { error: true, message: string };
function handleResponse(response: Success | Failed) {
if (response.success) {
// $ExpectError
var value: boolean = response.value; // Error!
}
}
這是因為在Flow中傳遞一個屬性比對象類型期望的屬性多的對象值是可以的(因為寬度子類型)。
// @flow
type Success = { success: true, value: boolean };
type Failed = { error: true, message: string };
function handleResponse(response: Success | Failed) {
// ...
}
handleResponse({
success: true,
error: true,
value: true,
message: 'hi'
});
除非這些物體在某種程度上相互沖突,否則就沒有辦法區(qū)分它們起惕。
但是涡贱,要解決這個問題,您可以使用精確的對象類型惹想。
// @flow
type Success = {| success: true, value: boolean |};
type Failed = {| error: true, message: string |};
type Response = Success | Failed;
function handleResponse(response: Response) {
if (response.success) {
var value: boolean = response.value;
} else {
var message: string = response.message;
}
}
有了精確的對象類型问词,我們就不可能有額外的屬性,所以對象之間會發(fā)生沖突嘀粱,我們就能區(qū)分出哪個是哪個激挪。