我最近看了一个关于使用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数据并绑定到接口/模型。有时我想要单个数据对象,有时我想保存对象的数组。

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


当前回答

当您只是想检查数据类型以确保响应始终具有必要的键时,请使用interface。类/模型不仅仅用于检查数据类型。另外,很高兴知道javascript中不存在接口,这意味着typescript将总是在编译时处理接口,不选择javascript原生的类。

其他回答

当您只是想检查数据类型以确保响应始终具有必要的键时,请使用interface。类/模型不仅仅用于检查数据类型。另外,很高兴知道javascript中不存在接口,这意味着typescript将总是在编译时处理接口,不选择javascript原生的类。

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

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

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

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

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

接口只在编译时存在。这只允许您检查接收到的预期数据是否遵循特定的结构。为此,你可以将你的内容转换到这个接口:

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

请看这些问题:

如何将JSON对象转换为typescript类 如何获得日期对象从json响应在typescript

你可以对class做一些类似的事情,但与class的主要区别是它们是在运行时出现的(构造函数),你可以用processing在它们中定义方法。但是,在这种情况下,你需要实例化对象才能使用它们:

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

我个人在我的模型中使用接口,但是关于这个问题有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
}

如果你使用的是Angular 4.3中的HttpClient和HttpClientModule,那么映射服务器到接口的响应就很简单了。X及以上。

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

何时使用接口:

You only need the definition for the server data without introducing additional overhead for the final output. You only need to transmit data without any behaviors or logic (constructor initialization, methods) You do not instantiate/create objects from your interface very often Using simple object-literal notationlet instance: FooInterface = { ... };, you risk having semi-instances all over the place. That doesn't enforce the constraints given by a class ( constructor or initialization logic, validation, encapsulation of private fields...Etc) You need to define contracts/configurations for your systems (global configurations)

2 -类:

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

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的最新版本,接口和类型变得越来越相似。 类型不表示应用程序内部的逻辑或状态。当您想要描述某种形式的信息时,最好使用类型。它们可以描述不同形状的数据,从简单的结构,如字符串、数组和对象。 和接口一样,类型只是虚拟结构,不能编译成任何javascript,它们只是帮助编译器使我们的工作更简单。

type FamilySituation = 'single' | 'married' | 'divorced' | 'widow' ;...
type User = {
 id: number;
 username: string;
}
// inheritance
type UserDetails = User & {
  birthDate: Date;
  familySituation: FamilySituation ;
}

何时使用类型:

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