为什么我应该在 Typescript / Angular 中使用接口(模型)?

问题描述 投票:0回答:3

在我看来,用模型定义对象似乎使它们变得僵化且不易更改,从而更容易在将来破坏应用程序并添加代码行而没有任何好处。例如,我可以有一个 get 方法,该方法从 API 返回视频对象,并将其编程为 Any 或定义的模型。

/模型/video.ts

export interface Video {
// my code
 }

/pages/videos.ts

getAllVideos(): Promise<Video> {
// my code
}

/pages/videos.ts

getAllVideos(): Promise<Any> {
// my code
}

我的看法。更少的代码行、更少的复杂性、更少的文件和更少的刚性是一件好事。为什么还要定义模型?

angular typescript angular5 angular6
3个回答
11
投票

...使将来更容易破坏应用程序...

这与使用 Typescript 向 JS 引入接口时发生的情况完全相反。

假设您有一个接受具有特定形状的对象的函数,就像这样

function giveMeStuff(obj) {
  return obj.foo.toLowerCase();
}

在这种情况下,我们无法确保当我们调用

giveMeStuff
时,我们实际上传递的是一个具有
foo
属性的对象,该对象也需要是一个字符串。

如果新开发人员(或您自己,几周后)出现并调用

giveMeStuff(12)
,代码将在运行时中断。


相反,当你有一个界面时就会发生这种情况。

function giveMeStuff(obj: IObjectWithFoo): string {
  return obj.foo.toLowerCase();
}

interface IObjectWithFoo {
  foo: string;
}

现在,当您尝试调用

giveMeStuff(12)
时,编译器会警告您不能这样做,因为该函数需要不同类型的参数。


3
投票

在某些情况下,拥有一个定义良好的界面更为重要。这取决于您要满足哪些要求、申请的风险等等。

例如,在特定项目中,强制对该对象类型使用该方法可能更重要,以减少错误概率。


0
投票

尚未包含在任何答案中的一个重要策略是使用接口来挖掘 API/服务响应数据结构契约/期望,从而有助于识别前端与后端对结构的期望之间的数据结构不匹配应该是。

如果您的应用程序使用异步服务/API 请求,您将无法在编译时直接使用接口来捕获错误,因为编译器不知道每个异步请求的响应是什么。如果没有抛出错误,您可能永远不会检测到数据类型差异。

但是,如果有一个使用

<interface-name>
类型的测试数据的明确定义的单元测试套件,Jasmine 和 Jest 将捕获测试数据的结构与根据接口的结构 应该是 之间的任何不匹配。在我看来,这是一种非常有用的数据挖掘服务端点/API 响应的方法,以帮助确保数据结构的前端和后端期望保持同步。这对于具有多个开发人员甚至多个团队执行不同任务的大型项目尤其重要。根据我的经验,在这些情况下数据模型的结构不同步是很常见的。团队流动和缺乏文档是这里的罪魁祸首。

您可以简单地从真实服务/API 响应中复制对象,并将其用作单元测试中的测试数据。

所以让我们在你的组件中说:

this.getData
.pipe(...)
.subscribe((resp: dataInterface[]) {
    this.allData = response;
});

...假设您有一个

spec.ts
,它使用
mockResponse
:

加载其组件
providers: [
    {
        provide: ServiceRequest,
        useValue: {
            getData: () => of(mockResponse)
        }
    }
], ...

并且有一个像这样的单元测试断言:

const mockResponse: dataInterface[] = [
    {
        a: "test1",
        b: "test2"
    }, ...
];

where 

export interface dataInterface {
    a: string;
    b: string;
}

此单元测试将通过:

expect(component.allData).toEqual(mockResponse);

现在假设随着时间的推移,随着团队的更替,新的团队成员将模拟响应更改为

const mockResponse: dataInterface[] = [
    {
        a: "test1" // b is removed
    }, ...
];

如果 IDE 没有标记这一点并引起开发人员的注意,Jasmine 编译器会。

这是我们团队应用程序的屏幕截图,其中名为

caseDetail
的界面需要名为
groupName
的属性。我直接从真实请求的响应中复制了服务响应,并将其复制到我的单元测试中。当我尝试运行测试套件时,Jasmine 编译器将测试数据标记为缺少此属性:

groupName property is flagged as missing from test data

这种差异可能永远不会被发现,因为我们的应用程序上没有任何功能实际上破坏了 b/c

groupName
在响应中丢失了。然后我就可以回到我们的后端开发人员那里并创建一个峰值来探索这种差异。

© www.soinside.com 2019 - 2024. All rights reserved.