何时在 TypeScript / Angular 中使用接口和模型

Posted

技术标签:

【中文标题】何时在 TypeScript / Angular 中使用接口和模型【英文标题】:When to use Interface and Model in TypeScript / Angular 【发布时间】:2016-10-05 18:54:53 【问题描述】:

我最近看了一个使用 TypeScript 的 Angular 2 教程,但不确定何时使用接口以及何时使用数据结构模型。

接口示例:

export interface IProduct 
    ProductNumber: number;
    ProductName: string;
    ProductDescription: string;

模型示例:

export class Product 
    constructor(
        public ProductNumber: number,
        public ProductName: string,
        public ProductDescription: string
    )

我想从 URL 加载 JSON 数据并绑定到接口/模型。有时我想要一个数据对象,有时我想保存一个对象数组。

我应该使用哪一个?为什么?

【问题讨论】:

在需要自定义逻辑初始化时使用类,否则总是使用接口,因为这仅在编译时可用。 typescript 接口未编译为 javascript,因为它在 javascript 中不存在。 请记住,在 Angular 2 中,接口不适用于依赖注入。在这里您必须使用类。 这篇文章codefeetime.com/post/typescript-class-or-interface-for-model 似乎建议您在大多数情况下都需要自定义逻辑。恕我直言,很好地涵盖了这个主题。 【参考方案1】:

接口仅在编译时。这仅允许您检查接收到的预期数据是否遵循特定结构。为此,您可以将内容投射到此界面:

this.http.get('...')
    .map(res => <Product[]>res.json());

查看这些问题:

How do I cast a JSON object to a typescript class How to get Date object from json Response in typescript

您可以对类执行类似的操作,但与类的主要区别在于它们存在于运行时(构造函数),并且您可以通过处理在其中定义方法。但是,在这种情况下,您需要实例化对象才能使用它们:

this.http.get('...')
    .map(res => 
      var data = res.json();
      return data.map(d => 
        return new Product(d.productNumber,
          d.productName, d.productDescription);
      );
    );

【讨论】:

感谢您的详细解答。如果接口只在编译时使用,编译器如何在不实际检查http get的情况下检查JSON文件的结构?如果它不能,那么即使打扰界面又有什么意义呢? @I_LIKE_FOO 编译器不需要检查 get 调用。它只关心检查它知道的类型以及它们是否正确对齐。 var data = res.json(); 对于编译器来说实际上是 var data: any = res.json();,所以我们失去了对 data 的所有类型检查。这里更有用的是 var data: ProductDto[] = res.json(); 之类的东西,ProductDto 是在返回的 json 中对数据结构进行建模的接口。 是的,但问题是他们不是设计 Typescript 的大师之神。那将是微软和公司。他们倾向于在适当的时候支持接口和类。还有加分……一个是运行时,另一个是编译时 @Sampath 也许 Angular 样式指南已经更新,因为我现在看到这个“考虑使用数据模型的接口。”。暗示更喜欢数据模型的接口而不是类。 我遇到并似乎值得在这里分享的一件事是 - 因为接口只是编译时实体,并且从 dists 中的运行时包中删除,但类仍然存在于运行时 dist 中。我们的类被转译成它的 ES5 兼容函数形式,现在是我们最终 JavaScript 应用程序的一个不必要的部分。如果我们有一个大型应用程序,并重复使用类作为模型类型注释的这种模式,那么我们最终可能会给用户的包添加大量额外的膨胀。【参考方案2】:

接口描述或新类型的契约。 它是一个纯 Typescript 元素,因此不会影响 Javascript。

一个模型,也就是一个,是一个用于生成新对象的实际JS函数。

我想从 URL 加载 JSON 数据并绑定到接口/模型。

选择一个模型,否则它在你的 Javascript 中仍然是 JSON。

【讨论】:

【参考方案3】:

使用类代替接口,这是我经过所有研究后发现的。

为什么?一个单独的类比一个类加接口的代码少。 (无论如何,您可能需要一个数据模型类)

为什么?类可以充当接口(使用实现而不是扩展)。

为什么?接口类可以是 Angular 依赖注入中的提供者查找标记。

from Angular Style Guide

基本上一个类可以做所有的事情,一个接口会做什么。 因此可能永远不需要使用接口

【讨论】:

Angular 风格指南目前实际上说,“考虑为数据模型使用接口 @AlexPeters 请提供任何真实的链接。提前致谢 @AnandPhadke 当然,这是我在上面发表评论时的 Angular 风格指南 a Wayback Machine link。【参考方案4】:

正如@ThierryTemplier 所说,用于从服务器接收数据并在组件之间传输模型(以保留智能感知列表并产生设计时错误),使用接口很好,但我认为将数据发送到服务器(DTO)最好使用类利用模型中的自动映射 DTO。

【讨论】:

【参考方案5】:

我个人为我的模型使用接口,关于这个问题有 3 所学校,通常根据您的要求选择一个:

1- 接口:

interface 是一个仅存在在 TypeScript 上下文中的虚拟结构。 TypeScript 编译器仅将接口用于类型检查。一旦你的代码被转译成它的目标语言,它就会从它的接口中被剥离——JavaScript 不是类型化的。

interface User 
 id: number;
 username: string;

// inheritance
interface UserDetails extends User 
 birthdate: Date;
 biography?: string;  // use the '?' annotation to mark this property as optionnal

如果您使用的是 HttpClient,则将服务器响应映射到 interface 非常简单,如果您使用的是 Angular 4.3.x 及更高版本,则从 HttpClientModule 开始。

getUsers() :Observable<User[]> 
 return this.http.get<User[]>(url); // no need for '.map((res: Response) => res.json())' 

何时使用接口:

您只需要定义服务器数据,而不会为最终输出引入额外开销。 您只需要传输数据,无需任何行为或逻辑(构造函数初始化、方法) 您不会经常从界面实例化/创建对象 使用简单的对象文字表示法let instance: FooInterface = ... ;,您可能会冒着到处都有半实例的风险。 这不会强制执行类给出的约束(构造函数或初始化逻辑、验证、私有字段的封装...等) 您需要为您的系统定义合同/配置(全局配置)

2- 类:

class 定义对象的蓝图。它们表达了这些对象将继承的逻辑、方法和属性。

class User 
 id: number;
 username: string;
 constructor(id :number, username: string)  
  this.id = id;
  this.username = username.replace(/^\s+|\s+$/g, ''); // trim whitespaces and new lines
 

// inheritance
class UserDetails extends User 
 birthdate: Date;
 biography?: string;  
 constructor(id :number, username: string, birthdate:Date, biography? :string )  
   super(id,username);
  this.birthdate = ...;
 

何时使用类:

您实例化您的类并随着时间的推移更改实例状态。 您的类的实例将需要查询或改变其状态的方法 当您希望将行为与数据更紧密地关联起来时; 您对实例的创建实施约束。 如果您只在类中编写一堆属性分配,您可以考虑改用类型。

2- 类型:

随着最新版本的 typescript,接口和类型变得更加相似。 types 不要在应用程序内部表达逻辑或状态。当您想描述某种形式的信息时,最好使用类型。它们可以描述不同形状的数据,包括字符串、数组和对象等简单结构。 与接口一样,类型只是不会转译为任何 javascript 的虚拟结构,它们只是帮助编译器让我们的生活更轻松。

type User = 
 id: number;
 username: string;

// inheritance
type UserDetails = User & 
  birthDate :Date;
  biography?:string;

何时使用类型:

将其作为简洁的函数参数传递 描述一个类的构造函数参数 记录从 API 传入或传出的中小型对象。 它们不携带状态或行为

【讨论】:

【参考方案6】:

为了使您的代码灵活,我们需要使用接口。 创建接口并在类的构造函数中传递接口类型。这使用依赖注入。

好处:

    如果接口的参数有变化,不需要改变类。 2.为了测试,您可以在类的构造函数中使用模拟数据。

【讨论】:

以上是关于何时在 TypeScript / Angular 中使用接口和模型的主要内容,如果未能解决你的问题,请参考以下文章

何时在 Angular2 打字稿中创建构造函数?

何时在 Angular 项目中使用类或接口? [关闭]

何时在 TypeScript 中使用类与模块?

TypeScript - 何时使用目标版本?

何时使用TypeScript:常见场景的详细介绍

何时在 Angular 中使用 transclude 'true' 和 transclude 'element'?