接口類型
Flow中的類名義上是鍵入的懂讯。這意味著當(dāng)你有兩個(gè)單獨(dú)的類時(shí)圾叼,即使它們具有相同的屬性和方法相恃,也不能使用一個(gè)類代替另一個(gè)钝满。
// @flow
class Foo {
serialize() { return '[Foo]'; }
}
class Bar {
serialize() { return '[Bar]'; }
}
// $ExpectError
const foo: Foo = new Bar(); // Error!
相反,您可以使用接口來(lái)聲明您期望的類的結(jié)構(gòu)袖扛。
// @flow
interface Serializable {
serialize(): string;
}
class Foo {
serialize() { return '[Foo]'; }
}
class Bar {
serialize() { return '[Bar]'; }
}
const foo: Serializable = new Foo(); // Works!
const bar: Serializable = new Bar(); // Works!
您還可以使用implements來(lái)告訴Flow您希望該類與接口匹配砸泛。這可以防止您在編輯類時(shí)進(jìn)行不兼容的更改。
// @flow
interface Serializable {
serialize(): string;
}
class Foo implements Serializable {
serialize() { return '[Foo]'; } // Works!
}
class Bar implements Serializable {
// $ExpectError
serialize() { return 42; } // Error!
}
您還可以使用具有多個(gè)接口的工具蛆封。
class Foo implements Bar, Baz {
// ...
}
接口語(yǔ)法
接口是使用關(guān)鍵字interface唇礁,后跟其名稱和包含類型定義主體的塊創(chuàng)建的。
interface MyInterface {
// ...
}
塊的語(yǔ)法與對(duì)象類型的語(yǔ)法匹配惨篱,并具有所有相同的功能
接口方法
您可以按照與對(duì)象方法相同的語(yǔ)法向接口添加方法盏筐。
interface MyInterface {
method(value: string): number;
}
接口屬性
您可以按照與對(duì)象屬性相同的語(yǔ)法向接口添加屬性。
interface MyInterface {
property: string;
}
接口屬性也是可選的砸讳。
interface MyInterface {
property?: string;
}
接口Maps
您可以使用與對(duì)象相同的方式創(chuàng)建“索引器屬性”琢融。
interface MyInterface {
[key: string]: number;
}
接口泛型
接口也可以有自己的泛型界牡。
interface MyInterface<A, B, C> {
property: A;
method(val: B): C;
}
接口泛型已參數(shù)化。使用接口時(shí)漾抬,需要為每個(gè)泛型傳遞參數(shù)宿亡。
// @flow
interface MyInterface<A, B, C> {
foo: A;
bar: B;
baz: C;
}
var val: MyInterface<number, boolean, string> = {
foo: 1,
bar: true,
baz: 'three',
};
接口屬性變量(只讀和只寫)
默認(rèn)情況下,接口屬性是不變的奋蔚。但是您可以添加修飾符以使它們協(xié)變(只讀)或逆變(只寫)她混。
interface MyInterface {
+covariant: number; // read-only
-contravariant: number; // write-only
}
接口上的協(xié)變(只讀)屬性
您可以通過(guò)在屬性名稱前添加加號(hào)+來(lái)使屬性協(xié)變。
interface MyInterface {
+readOnly: number | string;
}
這允許您傳遞更具體的類型來(lái)代替該屬性泊碑。
// @flow
// $ExpectError
interface Invariant { property: number | string }
interface Covariant { +readOnly: number | string }
var value1: Invariant = { property: 42 }; // Error!
var value2: Covariant = { readOnly: 42 }; // Works!
由于協(xié)方差的工作原理坤按,協(xié)變屬性在使用時(shí)也變?yōu)橹蛔x。這對(duì)普通屬性有用馒过。
// @flow
interface Invariant { property: number | string }
interface Covariant { +readOnly: number | string }
function method1(value: Invariant) {
value.property; // Works!
value.property = 3.14; // Works!
}
function method2(value: Covariant) {
value.readOnly; // Works!
// $ExpectError
value.readOnly = 3.14; // Error!
}
接口上的逆變(只寫)屬性
您可以通過(guò)在屬性名稱前添加減號(hào)來(lái)創(chuàng)建屬性逆變臭脓。
interface InterfaceName {
-writeOnly: number;
}
這允許您傳遞一個(gè)不太具體的類型來(lái)代替該屬性。
// @flow
interface Invariant { property: number }
interface Contravariant { -writeOnly: number }
var numberOrString = Math.random() > 0.5 ? 42 : 'forty-two';
// $ExpectError
var value1: Invariant = { property: numberOrString }; // Error!
var value2: Contravariant = { writeOnly: numberOrString }; // Works!
由于逆變的工作原理腹忽,逆變屬性在使用時(shí)也會(huì)變?yōu)橹粚懤蠢邸_@對(duì)普通屬性有用。
interface Invariant { property: number }
interface Contravariant { -writeOnly: number }
function method1(value: Invariant) {
value.property; // Works!
value.property = 3.14; // Works!
}
function method2(value: Contravariant) {
// $ExpectError
value.writeOnly; // Error!
value.writeOnly = 3.14; // Works!
}
泛型
泛型(有時(shí)稱為多態(tài)類型)是一種抽象類型的方法窘奏。 想象一下編寫以下身份函數(shù)嘹锁,它返回傳遞的任何值。
function identity(value) {
return value;
}
我們?cè)趪L試為此函數(shù)編寫特定類型時(shí)會(huì)遇到很多麻煩着裹,因?yàn)樗赡苁侨魏螙|西领猾。
function identity(value: string): string {
return value;
}
相反,我們可以在函數(shù)中創(chuàng)建泛型(或多態(tài)類型)骇扇,并使用它代替其他類型摔竿。
function identity<T>(value: T): T {
return value;
}
泛型可以在函數(shù),函數(shù)類型少孝,類继低,類型別名和接口中使用。
警告:Flow不會(huì)推斷泛型類型稍走。如果您希望某些東西具有泛型類型袁翁,請(qǐng)對(duì)其進(jìn)行注釋。否則婿脸,F(xiàn)low可能會(huì)推斷出比您預(yù)期的多態(tài)性更低的類型粱胜。
在下面的示例中,我們忘記使用泛型類型正確地注釋 identity 盖淡,因此當(dāng)我們嘗試將其分配給func時(shí)會(huì)遇到麻煩年柠。另一方面凿歼,genericIdentity已正確輸入褪迟,我們可以按預(yù)期使用它冗恨。
// @flow
type IdentityWrapper = {
func<T>(T): T
}
function identity(value) {
return value;
}
function genericIdentity<T>(value: T): T {
return value;
}
// $ExpectError
const bad: IdentityWrapper = { func: identity }; // Error!
const good: IdentityWrapper = { func: genericIdentity }; // Works!
具有泛型的函數(shù)
函數(shù)可以通過(guò)在函數(shù)參數(shù)列表之前添加類型參數(shù)列表<T>來(lái)創(chuàng)建泛型。 您可以在函數(shù)(參數(shù)或返回類型)中添加任何其他類型的相同位置使用泛型味赃。
function method<T>(param: T): T {
// ...
}
function<T>(param: T): T {
// ...
}
具有泛型的函數(shù)類型
函數(shù)類型可以通過(guò)在函數(shù)類型參數(shù)列表之前添加類型參數(shù)list <T>掀抹,以與普通函數(shù)相同的方式創(chuàng)建泛型心俗。 您可以在函數(shù)類型(參數(shù)或返回類型)中添加任何其他類型的相同位置使用泛型傲武。
<T>(param: T) => T
然后將其用作自己的類型。
function method(func: <T>(param: T) => T) {
// ...
}
具有泛型的類
類可以通過(guò)將類型參數(shù)列表放在類的主體之前來(lái)創(chuàng)建泛型城榛。
class Item<T> {
// ...
}
您可以在類中添加任何其他類型的相同位置使用泛型(屬性類型和方法參數(shù)/返回類型)揪利。
class Item<T> {
prop: T;
constructor(param: T) {
this.prop = param;
}
method(): T {
return this.prop;
}
}
具有泛型的類型別名
type Item<T> = {
foo: T,
bar: T,
};
具有泛型的接口
interface Item<T> {
foo: T,
bar: T,
}
泛型特性
泛型就像變量一樣
泛型類型很像變量或函數(shù)參數(shù),除了它們用于類型狠持。只要它們?cè)诜秶鷥?nèi)疟位,您就可以使用它們。
function constant<T>(value: T) {
return function(): T {
return value;
};
}
根據(jù)需要?jiǎng)?chuàng)建盡可能多的泛型
您可以在類型參數(shù)列表中根據(jù)需要使用這些泛型喘垂,并根據(jù)需要命名它們:
function identity<One, Two, Three>(one: One, two: Two, three: Three) {
// ...
}
泛型跟蹤
當(dāng)對(duì)值使用泛型類型時(shí)甜刻,F(xiàn)low將跟蹤該值并確保您不會(huì)將其替換為其他值。
// @flow
function identity<T>(value: T): T {
// $ExpectError
return "foo"; // Error!
}
function identity<T>(value: T): T {
// $ExpectError
value = "foo"; // Error!
// $ExpectError
return value; // Error!
}
Flow跟蹤您通過(guò)泛型的值的特定類型正勒,以便稍后使用得院。
// @flow
function identity<T>(value: T): T {
return value;
}
let one: 1 = identity(1);
let two: 2 = identity(2);
// $ExpectError
let three: 3 = identity(42);
將類型添加到泛型
與 mixed 類似,泛型具有“未知”類型章贞。您不能使用泛型祥绞,就好像它是特定類型一樣。
// @flow
function logFoo<T>(obj: T): T {
// $ExpectError
console.log(obj.foo); // Error!
return obj;
}
您可以優(yōu)化類型阱驾,但泛型仍然允許傳入任何類型就谜。
// @flow
function logFoo<T>(obj: T): T {
if (obj && obj.foo) {
console.log(obj.foo); // Works.
}
return obj;
}
logFoo({ foo: 'foo', bar: 'bar' }); // Works.
logFoo({ bar: 'bar' }); // Works. :(
相反,您可以像使用函數(shù)參數(shù)一樣為泛型添加類型里覆。
// @flow
function logFoo<T: { foo: string }>(obj: T): T {
console.log(obj.foo); // Works!
return obj;
}
logFoo({ foo: 'foo', bar: 'bar' }); // Works!
// $ExpectError
logFoo({ bar: 'bar' }); // Error!
這樣丧荐,您可以保留泛型的行為,同時(shí)僅允許使用某些類型喧枷。
// @flow
function identity<T: number>(value: T): T {
return value;
}
let one: 1 = identity(1);
let two: 2 = identity(2);
// $ExpectError
let three: "three" = identity("three");
泛型充當(dāng)邊界
// @flow
function identity<T>(val: T): T {
return val;
}
let foo: 'foo' = 'foo'; // Works!
let bar: 'bar' = identity('bar'); // Works!
在Flow中虹统,大多數(shù)情況下,當(dāng)您將一種類型傳遞到另一種類型時(shí)隧甚,您將失去原始類型车荔。因此,當(dāng)您將特定類型傳遞給不太具體的一個(gè)流程“界限”時(shí)戚扳,它曾經(jīng)是更具體的東西忧便。
// @flow
function identity(val: string): string {
return val;
}
let foo: 'foo' = 'foo'; // Works!
// $ExpectError
let bar: 'bar' = identity('bar'); // Error!
泛型允許您在添加約束時(shí)保留更具體的類型。通過(guò)這種方式帽借,泛型上的類型充當(dāng)“邊界”珠增。
// @flow
function identity<T: string>(val: T): T {
return val;
}
let foo: 'foo' = 'foo'; // Works!
let bar: 'bar' = identity('bar'); // Works!
請(qǐng)注意超歌,如果您具有綁定泛型類型的值,則不能將其用作更具體的類型蒂教。
// @flow
function identity<T: string>(val: T): T {
let str: string = val; // Works!
// $ExpectError
let bar: 'bar' = val; // Error!
return val;
}
identity('bar');
參數(shù)化泛型
泛型有時(shí)允許您將類似參數(shù)的類型傳遞給函數(shù)巍举。這些被稱為參數(shù)化泛型(或參數(shù)多態(tài))。
例如凝垛,參數(shù)化具有泛型的類型別名懊悯。當(dāng)你去使用它時(shí),你必須提供一個(gè)類型參數(shù)梦皮。
type Item<T> = {
prop: T,
}
let item: Item<string> = {
prop: "value"
};
您可以將此視為將函數(shù)傳遞給函數(shù)炭分,只有返回值是您可以使用的類型。
類(當(dāng)用作類型時(shí))剑肯,類型別名和接口都要求您傳遞類型參數(shù)欠窒。函數(shù)和函數(shù)類型沒(méi)有參數(shù)化泛型。
classes
// @flow
class Item<T> {
prop: T;
constructor(param: T) {
this.prop = param;
}
}
let item1: Item<number> = new Item(42); // Works!
// $ExpectError
let item2: Item = new Item(42); // Error!
Type Aliases 類型別名
// @flow
type Item<T> = {
prop: T,
};
let item1: Item<number> = { prop: 42 }; // Works!
// $ExpectError
let item2: Item = { prop: 42 }; // Error!
接口
// @flow
interface HasProp<T> {
prop: T,
}
class Item {
prop: string;
}
(Item.prototype: HasProp<string>); // Works!
// $ExpectError
(Item.prototype: HasProp); // Error!
添加參數(shù)化泛型的默認(rèn)值
您還可以像參數(shù)函數(shù)一樣為參數(shù)化泛型提供默認(rèn)值退子。
type Item<T: number = 1> = {
prop: T,
};
let foo: Item<> = { prop: 1 };
let bar: Item<2> = { prop: 2 };
使用類型時(shí)岖妄,必須始終包括括號(hào)<>(就像函數(shù)調(diào)用的括號(hào)一樣)。