【问题标题】:Difference between interfaces and classes in TypescriptTypescript 中接口和类的区别
【发布时间】:2017-04-19 18:38:05
【问题描述】:

Typescript 接口和类之间有什么区别?我什么时候使用 一类?我什么时候使用接口?它们的优点是什么?

我需要为后端服务器的 http 请求创建某种类型(使用 Angular 2 执行),例如: },

"fields": {
  "project": {
      "id": "10000"
  },
  "summary": "something's wrong",
  "issuetype": {
      "id": "10000"
  },
  "assignee": {             // not neccesary required
      "name": "homer"
  },
  "reporter": {
      "name": "smithers"
  },
  "priority": {            // not neccesary required
      "id": "20000"
  }
}

我应该使用什么来构建这些模型?谢谢!

【问题讨论】:

  • 我建议您先阅读一些有关 OOP 原则的内容。也许可以通过 typescript 手册阅读一下。接口和类章节应该会有所帮助。 :)
  • 最好参考这个链接johnpapa.net/typescriptpost3
  • 如果您只需要为您发布的这个结构提供类型安全,请使用接口。如果您想为这些实例提供方法,请使用类

标签: angular typescript class interface model


【解决方案1】:

根据Angular 2 styleguide,建议使用Class 而不是Interface 进行打字。主要区别在于class 在编译时会持续存在,而Interface 会被完全删除,因为它们没有任何用途。

在整个项目中保持一致,并更喜欢class 的样式指南方法,谁知道,也许有一天你需要将method 添加到你的models

查看以下答案了解更多详情:https://stackoverflow.com/a/55505227/5463904

【讨论】:

  • angular 风格指南没有说明使用class 而不是interface 的原因。它说“考虑”您的要求。在这里阅读更多:github.com/angular/angular/issues/19632
  • “谁知道呢,也许有一天你需要为你的模型添加方法。”接口也支持方法。
【解决方案2】:

使用打字稿而不是类来制作数据模型,因为编译器不会在运行时为接口生成任何相应的 JavaScript 代码。而如果你只使用一个类来制作数据模型,那么编译器会为它创建相应的 JS 代码,因此会消耗内存。

Angular 风格指南中的 sn-p:https://angular.io/guide/styleguide#interfaces

“考虑使用类而不是服务的接口和 可声明的(组件、指令和管道)。”

"考虑为数据模型使用接口。"

【讨论】:

    【解决方案3】:

    我在过去 2 年使用 angular,简而言之,当我想向我的对象添加任何行为时,我使用类,例如在我想添加返回已处理数据的 get 方法的任何类中,并且当没有添加任何行为时对象,我想直接访问对象我将使用接口.. 如果您定义构造函数,则使用类限制用户在构造任何对象之前定义要初始化的某些变量。

    【讨论】:

      【解决方案4】:

      Simply Class 是用来创建对象的,Interface 会帮助你这些对象应该包含什么。

      类就像一个蓝图/模板,我们可以使用它来创建对象。 接口就像一个合约,一个类必须同意实现该接口或定义该蓝图应包含的内容。

      一个简单的类:

      class Car {
          engine: string; // 'var' is not used;
      
          constructor(engine: string) { // This is how we create constructor
              this.engine = engine;
          }
      
          display(): void { // 'function' keyword is not used here.
              console.log(`Engine is ${this.engine}`); // just a log.
          }
      }
      
      var objCar = new Car('V8'); // creates new onject
      objCar.display(); // output: Engine is V8
      console.log(objCar.engine); // output: V8 (accessing member here)
      

      一个简单的界面:

          interface IPerson { // This is how we create an interface.
              firstName: string, // use commas to separate.
              lastName: string, // In classes we use semi-colon to separate.
              displayDetails: (number) => string
          }
      
          // We are going to store 'interface object' in a variable.
          // i.e. we are implementing interface with variable(not class!!)
          var customer: IPerson = {
      
              firstName: 'jose jithin', // 'implements' variables
              lastName: 'stanly',
      
              // Now method implementation.
              // Note: the syntax of 'displayDetails' maybe a bit confusing (given below)
              // as two colons are used.
              // It specifies a return type(string) here for this method. 
              displayDetails: (rank): string => { return `This person has rank ${rank}. ` }  
      
              // It can be rewritten as following too.
              displayDetails: (rank) => { return `This person has rank ${rank}. ` };
              // i.e. return type need not be specified, just like a normal method definition syntax.
          }
      
          console.log(customer.firstName); // output: jose jithin
      
          console.log(customer.lastName);  // output: stanly
      
          console.log(customer.displayDetails(1)); // output: This person has rank 
      

      我用article 详细介绍了类和接口。这可能有助于您理解。

      【讨论】:

        【解决方案5】:

        2019:差异和用法更新

        首先,有一个明显的区别:语法。这是一个简单但需要理解的区别:接口属性可以以逗号或分号结尾,但是类属性只能以分号结尾。现在有趣的东西。关于何时使用和不使用的部分可能是主观的——这些是我给我团队成员的指导方针,但其他团队可能会出于正当理由有其他指导方针。如果您的团队有不同的做法,请随时发表评论,我很想了解原因。

        接口:允许定义将在设计和编译期间用于强类型的类型。它们可以被“实现”或“扩展”,但不能被实例化(你不能new它们)。它们在转译为 JS 时会被删除,因此它们不占用空间,但它们也无法在运行时进行类型检查,因此您无法检查变量是否在运行时实现特定类型(例如 foo instanceof bar),除非通过检查它具有的属性:Interface type check with Typescript

        何时使用接口:当您需要为将在代码中多个位置(尤其是多个文件)中使用的对象创建属性和函数的协定时使用它们或功能。此外,当您希望其他对象以该基本属性集开始时使用,例如具有多个类实现为特定类型车辆的Vehicle 接口,如CarTruckBoat(例如@ 987654331@).

        何时不使用接口:当您希望拥有默认值、实现、构造函数或函数(不仅仅是签名)时。

        :还允许定义将在设计和编译时用于强类型的类型,此外,还可以在运行时使用。这也意味着代码没有编译出来,所以会占用空间。这是@Sakuto 提到的一个关键区别,但其含义不仅仅是空间。这意味着可以对类进行类型检查,即使在转译的 JS 代码中也能保留对“他们是谁”的理解。进一步的区别包括:类可以使用new 进行实例化,并且可以扩展,但不能实现。类可以有构造函数和实际的函数代码以及默认值。

        何时使用类:当您想要创建具有实际功能代码的对象、具有用于初始化的构造函数和/或想要使用new 创建它们的实例时。此外,对于简单的数据对象,您可以使用类来设置默认值。另一个你想使用它们的时候是在进行类型检查时,尽管如果需要,接口有一些变通方法(请参阅接口部分 OS 链接)。

        什么时候不使用类:当你有一个简单的数据接口时,不需要实例化它,当你想让它被其他对象实现时,当你想简单地放一个接口时在现有对象上(想想类型定义文件),或者当它占用的空间过高或没有根据时。附带说明一下,如果您查看 .d.ts 文件,您会注意到它们仅使用接口和类型,因此在转译为 TS 时会完全删除。

        最后说明,除了类和接口之外,还有两个选项,第一个是称为“类型”的东西,它与接口非常相似,但请查看此 SO 帖子,特别是2019 更新答案:Typescript: Interfaces vs Types。最后一个选择是采用 TS 的函数式编程风格(不是 OOP)。

        有关示例的完整故事,请访问PassionForDev.com,有关类与继承的更多好读物,请访问https://jameshenry.blog/typescript-classes-vs-interfaces/

        【讨论】:

        • 我刚刚发现类的 instanceof 很有趣,您必须创建一个类的新实例才能检查类型,而不仅仅是将其用作类型。当您考虑时,这似乎很明显,但是当我尝试编写示例时犯了错误。因此const classExample1: ClassExample = { status: 200 } 不能与instanceof 一起使用,但const classExample2 = new ClassExample() 可以。
        • 铸造@Jeremy 怎么样?即{} as User
        • @TR3B,您是在问当您执行{} as User casting 时TS 中会发生什么? User 是什么?这会告诉 TS 它是一个接口还是一个类——不过我不确定我是否理解你的问题。
        • @TR3B,我考虑了更多,当您执行{} as User 时,您实际上是将类型视为接口,即使它是一个类。如果它是一个类,它只会被类型转换使用,不会接收类的任何功能,把它当作一个只定义类型结构的接口。
        • @Jeremy 我对 TS 很陌生,但想添加到您的选角评论中。我正在构建一个 API,遇到了一个问题,即接口中的属性比源对象中的属性少(我从数据库中查询它,因此源类型是具有属性 id, username, password 的用户模型类)。我想从应用程序中提取数据库逻辑并创建一个没有密码的 DTO,当我转换到该 DTO 时,password 字段保留在对象中(包括类和 IF)。但是当你用new创建一个类实例时,你就可以在构造函数中使用你想要的字段了。
        【解决方案6】:

        我发现在使用classes 而不是interfaces 时类型安全性没有那么强,特别是对于在 React 中作为 prop 传递的函数签名。

        【讨论】:

          【解决方案7】:

          接口

          • 描述对象的外观
          • 仅存在编译时,其唯一目的是进行类型检查

          • 用作实例化/生成对象的蓝图
          • 可以实现接口,这意味着它必须至少实现接口中的所有属性/方法

          示例:

          interface Person {
              name: string;
              id: number;
              doStuff: () => void;
          }
          
          // implements Person says: You have to at least implement these things
          // which are located on the person interface 
          class employee implements Person {
              constructor(public name: string, public id: number){}
          
              doStuff () {console.log('Doing stuff')}
          }
          
          // interfaces can also describe variables and parameters
          const p1: Person = {
              name: 'foo',
              id: 34,
              doStuff () {console.log('Doing stuff')}
          }
          

          【讨论】:

            【解决方案8】:

            所以类和接口有很多不同。

            其中很少有:

            定义
            TypeScript 类是一个模板,它包含方法、变量并为对象提供骨架。 TypeScript 接口是一个蓝图,它将告诉派生类要实现什么。

            实际使用

            类:明智地设计模块功能框架
            接口:隐藏外部访问资源和保护核心逻辑的复杂性

            可实例化

            类:我们可以使用它的对象实例化类
            接口:我们不能实例化接口

            您可以在https://codetopology.com/scripts/typescript/typescript-interface-vs-class/找到更多不同之处

            【讨论】:

              【解决方案9】:

              TypeScript 中的接口有两个用途:

              1. 类的蓝图(例如,class Foo implements IFoo
              2. “类型化对象”(例如,let foo: IFoo = { … }

              #1 是“经典”目的,见于 Java、C# 等:接口只是描述了类的外观。它不是直接实例化的或任何东西。

              #2 是我至少在 TypeScript 中见过的东西:它基本上是一个经过编译时检查的字典。

              我的经验是 #2 会导致维护问题:您今天创建的那个简单的字典可能最终会用于方法,在这种情况下您必须更改所有调用者,这会扩大测试范围。

              我建议: 避免使用模式 #2 来处理 public 的事物,以支持类。作为内部编译时检查很好,但是通过促进方法的添加,您将有利于代码的未来维护者。当然,您可能永远不需要这些方法,但是当您这样做时,您会很高兴为自己留下了选择。

              【讨论】:

                猜你喜欢
                • 2012-12-30
                • 2018-10-11
                • 2021-03-16
                • 2012-10-18
                • 2015-02-15
                • 1970-01-01
                • 2017-04-09
                相关资源
                最近更新 更多