Classes in Flow are nominally typed. This means that when you have two separate classes you cannot use one in place of the other even when they have the same exact properties and methods.
// @flow class Foo { serialize() { return '[Foo]'; } } class Bar { serialize() { return '[Bar]'; } } // $ExpectError const foo: Foo = new Bar(); // Error!
Instead, you can use interface
in order to declare the structure of the class that you are expecting.
// @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!
You can also use implements
to tell Flow that you want the class to match an interface. This prevents you from making incompatible changes when editing the class.
// @flow interface Serializable { serialize(): string; } class Foo implements Serializable { serialize() { return '[Foo]'; } // Works! } class Bar implements Serializable { // $ExpectError serialize() { return 42; } // Error! }
You can also use implements
with multiple interfaces.
class Foo implements Bar, Baz { // ... }
Interfaces are created using the keyword interface
followed by its name and a block which contains the body of the type definition.
interface MyInterface { // ... }
The syntax of the block matches the syntax of object types and has all of the same features.
You can add methods to interfaces following the same syntax as object methods.
interface MyInterface { method(value: string): number; }
You can add properties to interfaces following the same syntax as object properties.
interface MyInterface { property: string; }
Interface properties can be optional as well.
interface MyInterface { property?: string; }
You can create “indexer properties” the same way as with objects.
interface MyInterface { [key: string]: number; }
Interfaces can also have their own generics.
interface MyInterface<A, B, C> { property: A; method(val: B): C; }
Interface generics are parameterized. When you use an interface you need to pass parameters for each of its generics.
// @flow interface MyInterface<A, B, C> { foo: A; bar: B; baz: C; } var val: MyInterface<number, boolean, string> = { foo: 1, bar: true, baz: 'three', };
Interface properties are invariant by default. But you can add modifiers to make them covariant (read-only) or contravariant (write-only).
interface MyInterface { +covariant: number; // read-only -contravariant: number; // write-only }
You can make a property covariant by adding a plus symbol +
in front of the property name.
interface MyInterface { +readOnly: number | string; }
This allows you to pass a more specific type in place of that property.
// @flow // $ExpectError interface Invariant { property: number | string } interface Covariant { +readOnly: number | string } var value1: Invariant = { property: 42 }; // Error! var value2: Covariant = { readOnly: 42 }; // Works!
Because of how covariance works, covariant properties also become read-only when used. Which can be useful over normal properties.
// @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! }
You can make a property contravariant by adding a minus symbol - in front of the property name.
interface InterfaceName { -writeOnly: number; }
This allows you to pass a less specific type in place of that property.
// @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!
Because of how contravariance works, contravariant properties also become write-only when used. Which can be useful over normal properties.
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! }
© 2013–present Facebook Inc.
Licensed under the MIT License.
https://flow.org/en/docs/types/interfaces