美文网首页
Flow接口类型(Interface Types)

Flow接口类型(Interface Types)

作者: vincent_z | 来源:发表于2018-01-25 22:17 被阅读0次

    接口类型(Interface Types)

    Flow中的类只是被名义上注解。这意味着,当你有两个单独的类时,即使它们具有相同的确切的属性和方法,也不能相互替代。

    // @flow
    class Foo {
      serialize() { return '[Foo]'; }
    }
    
    class Bar {
      serialize() { return '[Bar]'; }
    }
    
    // $ExpectError
    const foo: Foo = new Bar(); // Error!
    

    相反,你可以使用接口来声明你所期望的类的结构。

    // @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来告诉Flow你想让这个类匹配一个接口。 这可以防止编辑类时发生不兼容的更改。

    // @flow
    interface Serializable {
      serialize(): string;
    }
    
    class Foo implements Serializable {
      serialize() { return '[Foo]'; } // Works!
    }
    
    class Bar implements Serializable {
      // $ExpectError
      serialize() { return 42; } // Error!
    }
    

    你也可以实现多个接口。

    class Foo implements Bar, Baz {
      // ...
    }
    

    接口语法(Interface Syntax)

    interface MyInterface {
      // ...
    }
    
    接口方法(Interface Methods)
    interface MyInterface {
      method(value: string): number;
    }
    
    接口属性
    interface MyInterface {
      property: string;
      // property?: string;
     // [key: string]: number;
    }
    
    接口泛型(Interface Generics)
    interface MyInterface<A, B, C> {
      property: A;
      method(val: B): C;
    }
    

    接口泛型被参数化。当你使用一个接口时,你需要为每个泛型传递参数。

    // @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 MyInterface {
      +covariant: number;     // read-only
      -contravariant: number; // write-only
    }
    
    接口上的协变(只读)属性

    你可以通过在属性名称前添加加号+来创建属性协变。

    interface MyInterface {
      +readOnly: number | string;
    }
    
    // @flow
    // $ExpectError
    interface Invariant {  property: number | string }
    interface Covariant { +readOnly: number | string }
    
    var value1: Invariant = { property: 42 }; // Error!
    var value2: Covariant = { readOnly: 42 }; // Works!
    
    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!
    }
    

    接口上的逆变(只写)属性

    你可以通过在属性名称前添加加号-来创建属性协变。

    interface InterfaceName {
      -writeOnly: number;
    }
    
    // @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!
    
    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!
    }
    

    泛型(Generic Types)

    使用泛型添加抽象(多态)类型。

    泛型(有时被称为多态类型)是一种抽象类型的方法。

    下面的identity函数返回任何传入值。但你会发现很难为其定义特定类型,因为有无数种可能。

    function identity(value) {
      return value;
    }
    
    function identity(value: string): string {
      return value;
    }
    

    相反,我们可以在我们的函数中创建一个泛型(或多态类型),并用它来代替其他类型。

    function identity<T>(value: T): T {
      return value;
    }
    

    泛型可以在函数,函数类型,类,类型别名以及接口中使用。

    泛型语法

    泛型函数
    function method<T>(param: T): T {
      // ...
    }
    
    function<T>(param: T): T {
      // ...
    }
    
    泛型函数类型
    <T>(param: T) => T
    
    function method(func: <T>(param: T) => T) {
      // ...
    }
    
    泛型类
    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,
    }
    

    泛型行为

    泛型变量行为
    function constant<T>(value: T) {
      return function(): T {
        return value;
      };
    }
    
    泛型值跟踪
    // @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;
    }
    

    相反,你可以添加一个类型到你的泛型,就像你用一个函数参数。

    // @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!
    
    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");
    

    泛型类型绑定

    在Flow中,当你将一种类型传递给另一种时,多数情况下你会失去原有的类型。

    // @flow
    function identity(val: string): string {
      return val;
    }
    
    let foo: 'foo' = 'foo';           // Works!
    // $ExpectError
    let bar: 'bar' = identity('bar'); // Error!
    

    泛型允许你在添加约束的同时保持更具体的类型。 通过这种方式达到泛型的类型绑定。

    // @flow
    function identity<T: string>(val: T): T {
      return val;
    }
    
    let foo: 'foo' = 'foo';           // Works!
    let bar: 'bar' = identity('bar'); // Works!
    

    当一个值使用了泛型类型绑定时,你不能使用更具体的类型重新使用它。

    // @flow
    function identity<T: string>(val: T): T {
      let str: string = val; // Works!
      // $ExpectError
      let bar: 'bar'  = val; // Error!
      return val;
    }
    
    identity('bar');
    

    参数化泛型

    泛型有时候允许你将类型参数传递给一个函数。这些被称为参数化的泛型(或参数多态性)。

    当你去使用参数化泛型时,你需要提供一个类型参数。

    type Item<T> = {
      prop: T,
    }
    
    let item: Item<string> = {
      prop: "value"
    };
    

    类,类型别名和接口都需要传递类型参数。 函数和函数类型没有参数化泛型。

    // @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!
    
    类型别名
    // @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!
    
    参数化泛型默认参数
    type Item<T: number = 1> = {
      prop: T,
    };
    
    let foo: Item<> = { prop: 1 };
    let bar: Item<2> = { prop: 2 };
    

    相关文章

      网友评论

          本文标题:Flow接口类型(Interface Types)

          本文链接:https://www.haomeiwen.com/subject/xpvbaxtx.html