對象類型(Object Types)
對象類型語法
對象類型嘗試盡可能多地匹配JavaScript中的對象的語法。使用形式是:{鍵: 值}
秒梅。
// @flow
var obj1: { foo: boolean } = { foo: true };
var obj2: {
foo: number,
bar: boolean,
baz: string,
} = {
foo: 1,
bar: true,
baz: 'three',
};
對象類型可選屬性
在JavaScript中咸这,訪問不存在的屬性評估為undefined
焰枢。這是JavaScript程序中常見的錯誤來源王财,所以Flow會將這些錯誤轉(zhuǎn)化為類型錯誤忆矛。
// @flow
var obj = { foo: "bar" };
// $ExpectError
obj.bar; // Error!
添加一個可選屬性的方式是:{屬性名稱?: 類型}
察蹲。
// @flow
var obj: { foo?: boolean } = {};
obj.foo = true; // Works!
// $ExpectError
obj.foo = 'hello'; // Error!
可選屬性值可以是void
或省略,但是不能是null
// @flow
function acceptsObject(value: { foo?: string }) {
// ...
}
acceptsObject({ foo: "bar" }); // Works!
acceptsObject({ foo: undefined }); // Works!
// $ExpectError
acceptsObject({ foo: null }); // Error!
acceptsObject({}); // Works!
對象類型推導(dǎo)
Flow有兩種不同的方式推導(dǎo)出對象字面量的類型。
密封的對象(Sealed objects)
在Flow中創(chuàng)建一個密封的對象類型的方法是創(chuàng)建一個帶有屬性的對象递览。密封的對象知道你聲明的所有屬性及其值的類型叼屠。
// @flow
var obj = {
foo: 1,
bar: true,
baz: 'three'
};
var foo: number = obj.foo; // Works!
var bar: boolean = obj.bar; // Works!
// $ExpectError
var baz: null = obj.baz; // Error!
var bat: string = obj.bat; // Error!
Flow不允許你為密封對象添加新的屬性。
// @flow
var obj = {
foo: 1
};
// $ExpectError
obj.bar = true; // Error!
// $ExpectError
obj.baz = 'three'; // Error!
未密封的對象(Unsealed objects)
在Flow中創(chuàng)建一個未密封的對象類型的方法是創(chuàng)建一個帶沒有屬性的對象绞铃。未密封的對象不知道你聲明的所有屬性及其值的類型镜雨。
// @flow
var obj = {};
obj.foo = 1; // Works!
obj.bar = true; // Works!
obj.baz = 'three'; // Works!
未密封的對象允許你設(shè)置屬性。
// @flow
var obj = {};
obj.foo = 42;
var num: number = obj.foo;
為未密封對象屬性重新賦值
與var
和let
變量相似儿捧,你可以改變未密封的對象的屬性值荚坞。Flow會為你設(shè)置可能的類型。
// @flow
var obj = {};
if (Math.random()) obj.prop = true;
else obj.prop = "hello";
// $ExpectError
var val1: boolean = obj.prop; // Error!
// $ExpectError
var val2: string = obj.prop; // Error!
var val3: boolean | string = obj.prop; // Works!
當(dāng)Flow可以確定重新分配后的屬性類型時菲盾,F(xiàn)low會為其分配確定的類型颓影。
// @flow
var obj = {};
obj.prop = true;
obj.prop = "hello";
// $ExpectError
var val1: boolean = obj.prop; // Error!
var val2: string = obj.prop; // Works!
未密封對象上的未知屬性查找是不安全的
未密封的對象允許隨時寫入新的屬性。Flow確保讀取與寫入兼容懒鉴,但不能確保寫入發(fā)生在讀取之前(按執(zhí)行順序)诡挂。
這意味著從未被封裝的對象中讀取沒有匹配的寫入從不被檢查。這是Flow的不安全行為临谱,未來可能會有所改進(jìn)璃俗。
var obj = {};
obj.foo = 1;
obj.bar = true;
var foo: number = obj.foo; // Works!
var bar: boolean = obj.bar; // Works!
var baz: string = obj.baz; // Works?
確切的對象類型
在Flow中,在預(yù)期正常對象類型的情況下傳遞具有額外屬性的對象是安全的悉默。
// @flow
function method(obj: { foo: string }) {
// ...
}
method({
foo: "test", // Works!
bar: 42 // Works!
});
這是一種通常被稱為“寬度子類型”的子類型城豁,因為“更寬”(即具有更多屬性)的類型是更窄類型的子類型。
有時候阻止這種行為并且只允許一組特定的屬性是必要的抄课。為此唱星,F(xiàn)low有了以下的做法:
{| foo: string, bar: number |}
與常規(guī)對象類型不同,將具有“額外”屬性的對象傳遞給確切的對象類型是無效的跟磨。
// @flow
var foo: {| foo: string |} = { foo: "Hello", bar: "World!" }; // Error!
映射類(Map類)
JavaScript新標(biāo)準(zhǔn)增加了Map類间聊。在種情況下,一個對象可能會添加一些屬性抵拘,并在整個生命周期中被檢索甸饱。而且,屬性鍵甚至可能不被靜態(tài)檢查仑濒,所以寫出類型注釋是不可能的。對于像這樣的對象偷遗,F(xiàn)low提供了一種稱為“索引器屬性”的特殊屬性墩瞳。索引器屬性允許使用與索引器鍵類型匹配的任何鍵進(jìn)行讀取和寫入。
// @flow
var o: { [string]: number } = {};
o["foo"] = 0;
o["bar"] = 1;
var foo: number = o["foo"];
索引器可以被任意命名:
// @flow
var obj: { [user_id: number]: string } = {};
obj[1] = "Julia";
obj[2] = "Camille";
obj[3] = "Justin";
obj[4] = "Mark";
當(dāng)對象類型具有索引器屬性時氏豌,即使對象在運行時某個期間沒有值喉酌,屬性訪問也被假定為具有注釋類型。
var obj: { [number]: string } = {};
obj[42].length; // No type error, but will throw at runtime
索引器屬性可以與命名屬性混合使用:
// @flow
var obj: {
size: number,
[id: number]: string
} = {
size: 0
};
function add(id: number, name: string) {
obj[id] = name;
obj.size++;
}