在JavaScript中绞佩,對(duì)象可以以多種不同的方式使用寺鸥。為了支持所有不同的用例,有許多不同的方法可以輸入它們品山。
對(duì)象類型語(yǔ)法
對(duì)象類型盡可能地嘗試匹配JavaScript中對(duì)象的語(yǔ)法。使用冒號(hào)使用花括號(hào){}和名稱 - 值對(duì):用逗號(hào)分隔烤低,肘交。
// @flow
var obj1: { foo: boolean } = { foo: true };
var obj2: {
foo: number,
bar: boolean,
baz: string,
} = {
foo: 1,
bar: true,
baz: 'three',
};
注意:以前的對(duì)象類型使用分號(hào);用于拆分名稱 - 值對(duì)。雖然語(yǔ)法仍然有效扑馁,但您應(yīng)該使用逗號(hào)涯呻,
可選對(duì)象類型屬性
在JavaScript中,訪問不存在的屬性的計(jì)算結(jié)果為undefined腻要。這是JavaScript程序中常見的錯(cuò)誤來源复罐,因此Flow將這些錯(cuò)誤轉(zhuǎn)換為類型錯(cuò)誤。
// @flow
var obj = { foo: "bar" };
// $ExpectError
obj.bar; // Error! cannot get `obj.bar` beacuse property `bar` is missing in object litera [1].
如果您有一個(gè)有時(shí)沒有屬性的對(duì)象雄家,可以通過在對(duì)象類型中的屬性名稱之后添加問號(hào)使其成為可選屬性效诅。
// @flow
var obj: { foo?: boolean } = {};
obj.foo = true; // Works!
// $ExpectError
obj.foo = 'hello'; // Error! cannot assign `'hello'` to `obj.foo` because string [1] is incomptible with boolean [2]
除了它們的設(shè)置值類型之外,這些可選屬性可以是 void趟济,也可以完全省略乱投。但是,它們不能為 null顷编。
// @flow
function acceptsObject(value: { foo?: string }) {
// ...
}
acceptsObject({ foo: "bar" }); // Works!
acceptsObject({ foo: undefined }); // Works!
// $ExpectError
acceptsObject({ foo: null }); // Error!
acceptsObject({}); // Works!
密封對(duì)象
使用其屬性創(chuàng)建對(duì)象時(shí)戚炫,可在Flow中創(chuàng)建密封對(duì)象類型。這些密封對(duì)象將知道您聲明它們的所有屬性及其值的類型媳纬。
// @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!
但是當(dāng)對(duì)象被密封時(shí)双肤,F(xiàn)low將不允許您向它們添加新屬性。
// @flow
var obj = {
foo: 1
};
// $ExpectError
obj.bar = true; // Error!
// $ExpectError
obj.baz = 'three'; // Error!
此處的解決方法可能是將您的對(duì)象轉(zhuǎn)換為未密封的對(duì)象钮惠。
未密封對(duì)象
創(chuàng)建沒有任何屬性的對(duì)象時(shí)茅糜,可以在Flow中創(chuàng)建未密封的對(duì)象類型。這些未密封的對(duì)象不會(huì)知道它們的所有屬性萌腿,并允許您添加新屬性限匣。
// @flow
var obj = {};
obj.foo = 1; // Works!
obj.bar = true; // Works!
obj.baz = 'three'; // Works!
屬性的推斷類型(類型注釋)將成為您設(shè)置的屬性。
重新分配未密封的對(duì)象屬性
類似于var和let變量,如果重新分配未密封對(duì)象的屬性米死,默認(rèn)情況下锌历,F(xiàn)low會(huì)為其指定所有可能分配的類型。
// @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!
有時(shí)峦筒,F(xiàn)low能夠在重新分配后(確定地)確定屬性的類型究西。在這種情況下,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變得越來越聰明卤材,它將在更多場(chǎng)景中找出屬性的類型。
未密封對(duì)象上的未知屬性查找是不安全的
未密封的對(duì)象允許隨時(shí)寫入新屬性峦失。 Flow確保讀取與寫入兼容扇丛,但不確保在讀取之前發(fā)生寫入(按執(zhí)行順序)。
這意味著永遠(yuǎn)不會(huì)檢查沒有匹配寫入的未密封對(duì)象的讀取尉辑。這是Flow的一種不安全行為帆精,將來可能會(huì)得到改善。
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?
精確對(duì)象類型
在Flow中隧魄,傳遞具有額外屬性的對(duì)象被認(rèn)為是安全的卓练,其中期望正常的對(duì)象類型。
// @flow
function method(obj: { foo: string }) {
// ...
}
method({
foo: "test", // Works!
bar: 42 // Works!
});
有時(shí)禁用此行為并僅允許一組特定屬性很有用购啄。為此襟企,F(xiàn)low支持“精確”對(duì)象類型。
{| foo: string, bar: number |}
與常規(guī)對(duì)象類型不同狮含,將具有“額外”屬性的對(duì)象傳遞給精確對(duì)象類型無效顽悼。
// @flow
var foo: {| foo: string |} = { foo: "Hello", bar: "World!" }; // Error!
確切對(duì)象類型的交集可能無法按預(yù)期工作。如果需要組合確切的對(duì)象類型辉川,請(qǐng)使用對(duì)象類型傳播:
// @flow
type FooT = {| foo: string |};
type BarT = {| bar: number |};
type FooBarFailT = FooT & BarT;
type FooBarT = {| ...FooT, ...BarT |};
const fooBarFail: FooBarFailT = { foo: '123', bar: 12 }; // Error!
const fooBar: FooBarT = { foo: '123', bar: 12 }; // Works!
ObjectsAsMaps
較新版本的JavaScript標(biāo)準(zhǔn)包含一個(gè)Map類表蝙,但將對(duì)象用作Maps仍然很常見。在此用例中乓旗,對(duì)象可能會(huì)添加屬性并在其整個(gè)生命周期中檢索府蛇。此外,屬性鍵甚至可能不是靜態(tài)已知的屿愚,因此寫出類型注釋是不可能的汇跨。
對(duì)于像這樣的對(duì)象,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)對(duì)象類型具有索引器屬性時(shí)蚪黑,假定屬性訪問具有帶注釋的類型,即使該對(duì)象在運(yùn)行時(shí)沒有該槽中的值。程序員有責(zé)任確保訪問是安全的忌穿,就像數(shù)組一樣抒寂。
var obj: { [number]: string } = {};
obj[42].length; //沒有類型錯(cuò)誤,但會(huì)在運(yùn)行時(shí)拋出
索引器屬性可以與命名屬性混合使用:
// @flow
var obj: {
size: number,
[id: number]: string
} = {
size: 0
};
function add(id: number, name: string) {
obj[id] = name;
obj.size++;
}
Object Type
有時(shí)編寫接受任意對(duì)象的類型是有用的掠剑,對(duì)于那些你應(yīng)該寫{}的類似:
function method(obj: {}) {
// ...
}
但是屈芜,如果您需要選擇退出類型檢查程序,并且不想一直轉(zhuǎn)到任何類型檢查程序朴译,則可以改為使用Object井佑。Object 不安全,應(yīng)該避免眠寿。
例如躬翁,以下代碼不會(huì)報(bào)告任何錯(cuò)誤:
function method(obj: Object) {
obj.foo = 42; // Works.
let bar: boolean = obj.bar; // Works.
obj.baz.bat.bam.bop; // Works.
}
method({ baz: 3.14, bar: "hello" });