何时在 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 中使用接口和模型的主要内容,如果未能解决你的问题,请参考以下文章