【问题标题】:Why a object interface define is similar to class interface define in typescript为什么对象接口定义类似于打字稿中的类接口定义
【发布时间】:2016-01-31 23:35:10
【问题描述】:

我对 typescript 还很陌生,当我从它的 Playground 和界面部分学习它时,有一个困惑:

http://www.typescriptlang.org/Handbook#interfaces-our-first-interface-

http://www.typescriptlang.org/Handbook#interfaces-class-types

一个是说如何定义对象的接口,一个是为类定义,但是他们可以使用类似的结构,谁能指出为什么?

【问题讨论】:

    标签: typescript


    【解决方案1】:

    对象的接口,一个是为类定义的,但是它们可以使用类似的结构,谁能指出原因

    object 不了解创建者的运行时知识。而类实例知道它的构造函数。如下图所示:

    interface Foo {
        foo: number
    }
    
    let foo: Foo = { foo: 123 };
    
    class Bar {
        bar: number;
    }
    
    let bar: Bar = new Bar(); 
    bar.bar = 123;
    console.log(bar instanceof Bar); // True  
    

    这并没有改变打字稿是结构化的事实https://basarat.gitbook.io/typescript/content/docs/getting-started.html

    类也可以为您的代码提供更好的结构:https://basarat.gitbook.io/typescript/content/docs/classes.html

    【讨论】:

      【解决方案2】:

      在这两种情况下,接口都具有相同的目的 - 应用类型限制/优化。 “对象的接口”和“类的(或应用于)类的接口”没有区别。

      第一个例子展示了Structural Typing,没有引入类的概念:

      任何具有类型一致性结构的类型都满足接口契约1。

      .. 请注意,我们不必像在其他语言中那样明确地说我们传递给“printLabel”的[匿名创建]对象实现了这个接口。在这里,只有形状很重要。 如果我们传递给函数的对象[可以静态证明满足][在接口中]列出的要求,那么它是允许的。

      实现接口的类的实例隐式保证这个契约。将接口添加到类允许在类声明本身而不是仅在使用站点进行额外的约束检查:这可以实现更多本地化和有用的与类型相关的错误报告。


      1 这是一个静态/编译限制:对象的类型信息已经从对象字面量本身自动合成。实际运行时值与证明类型正确性无关。

      【讨论】:

      • 类在 TypeScript 中经过结构类型检查,不带有名义语义
      • @basarat:这不是真的。类可以展示结构类型和名义类型,具体取决于它们的编写方式。
      • @Puppy 您能否提供一个示例,说明类如何在 typescript 中具有nominal 性质。这是一个示例,说明类在结构上进行了类型检查:goo.gl/esa0rn
      【解决方案3】:

      它们具有相似的结构,但以不同的方式使用。该类允许您创建要在应用程序中使用的新对象。接口告诉编译器应该如何构造事物。您可以在下面看到您可以向标签属性添加值。您不能使用界面执行此操作。

      interface Something {
          label: string;
      }
      
      class Something {
          label: string = 'some string value';
      }
      

      在下面的示例中,接口强制Something 类始终需要名为label 的属性,并且类型必须是string。如果您更改类型或一起删除属性。编译器会报错。

      interface ISomething {
          label: string;
      }
      
      class Something implements ISomething {
          label: string = 'some string value';
      }
      

      在上面的示例中,我建议使用在接口名称前添加大写字母I 的约定,以消除类和接口之间的混淆。


      在下一个示例中,我们将使用一个接口 (IUser) 来允许将多个类传递给 getUserDescription 函数,而不会引起编译器的抱怨。这称为多态性。我们的函数不关心它是教师、学生还是任何其他班级。它只关心传入的结构是否与接口匹配。

      interface IUser {
          firstName: string;
          lastName: string;
          type: string;
      }
      
      class Student {
      
          firstName: string = null;
          lastName: string = null;
          type: string = 'student';
          courses: Array<any> = [];
      
          constructor(firstName: string, lastName: string) {
              this.firstName = firstName;
              this.lastName = lastName;
          }
      }
      
      class Teacher implements IUser {
      
          firstName: string = null;
          lastName: string = null;
          type: string = 'teacher';
          classes: Array<any> = [];
      
          constructor(firstName: string, lastName: string) {
              this.firstName = firstName;
              this.lastName = lastName;
          }
      }
      
      const getUserDescription = (user: IUser): string => {
          return `${user.firstName} ${user.lastName} is a ${user.type}`;
      };
      
      getUserDescription(new Teacher('Harry', 'Jones')); // Harry Jones is a teacher
      getUserDescription(new Student('Joe', 'Cool')); // Joe Cool is a student
      

      如果您注意到上面的 Teacher 实现了 IUser 但 Student 没有。通常你会以同样的方式完成,但我想表明你可以在班级级别强制执行结构。

      查看我的文章 http://www.codebelt.com/typescript/typescript-classes-object-oriented-programming/ 了解更多信息。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2023-02-07
        • 2018-02-22
        • 2016-08-29
        • 2023-01-05
        • 2021-08-24
        • 2016-12-28
        • 2019-10-31
        • 1970-01-01
        相关资源
        最近更新 更多