在C#中,接口和类之间存在巨大差异。实际上,类表示引用类型,因此我们实际上可以创建在该类上建模的对象,而接口则是类签名的合同,以确保存在某种行为。特别是我们无法创建接口实例。
接口的全部意义在于暴露行为。一个类通过给出一个所述行为的显式实现来实现它。
在这种情况下,虽然接口可能包含属性,但大多数时候我们都会因为行为问题而关心接口。所以大多数类型的接口都只是行为契约。
另一方面,在TypeScript上,我看起来让我感到非常不安,事实上我不止一次地看过这个,这就是这个问题的原因。
在一个教程中我看到了:
export interface User {
name: string; // required with minimum 5 chracters
address?: {
street?: string; // required
postcode?: string;
}
}
但等一下。为什么User
是一个界面?如果我们像C#一样思考,User
不应该是一个接口。事实上,看着它,似乎我们正在定义数据类型User
,而不是行为契约。
像在C#中一样思考,自然就是这样:
export class User {
public name: string;
public address: Address;
}
export class Address {
public street: string;
public postcode: string;
}
但是这样使用接口就像我们使用类一样,只是定义数据类型而不是定义行为契约,在TypeScript中似乎是非常常见的。
那么TypeScript中的接口是什么意思?为什么人们在TypeScript中使用接口,就像我们在C#中使用clases一样?如何在TypeScript中正确使用接口:建立行为契约,或者定义属性和对象应该有什么?
答案 0 :(得分:25)
考虑到在Javascript中,数据通常通过JSON交换为普通对象:
let data = JSON.parse(someString);
假设这个data
是User
个对象的数组,我们会将它传递给函数:
data.forEach(user => foo(user))
foo
的输入方式如下:
function foo(user: User) { ... }
但等等,我们没有做new User
!我们应该吗?我们是否必须将User
和map
所有data
写入其中,即使结果完全相同,也可以使用Object
属性?不,这只是为了满足类型系统而疯狂,但不会改变运行时的任何内容。一个简单的interface
描述了特定对象的外观(“表现”)就足够了。
答案 1 :(得分:12)
我也从C#背景来到Typescript并且想知道同样的事情。我正在考虑POCO(POTO是一件事吗?)
那么TypeScript中的接口是什么意思?
The Typescript Handbook似乎表示接口是用于“在代码中定义合同”。
为什么人们在TypeScript中使用接口,就像我们在C#中使用类一样?
我同意@ deceze的回答。
John Papa在他的blog上扩展了关于类和接口的主题。他建议类最适合“创建多个新实例,使用继承,[和]单例对象”。因此,根据Typescript手册中描述的Typescript接口的意图和一个人的意见,似乎没有必要在Typescript中建立合同。相反,您应该使用接口。 (你的C#意识仍然会被冒犯。)
接口应该在TypeScript中正确使用:建立行为契约,或者定义属性和对象应该有什么?
如果我理解了这个问题,那么您问的是接口是否应该建立行为 的合同或结构的合同。对此,我会回答:两者。 Typescript接口仍然可以像在C#或Java中使用接口一样使用(即描述类的行为),但它们也提供了描述数据结构的能力。
此外,我的同事让我使用类而不是接口,因为接口在编译器中不产生代码。
示例:
此打字稿:
class Car implements ICar {
foo: string;
bar(): void {
}
}
interface ICar {
foo: string;
bar(): void;
}
生成此Javascript:
var Car = (function () {
function Car() {
}
Car.prototype.bar = function () {
};
return Car;
}());
答案 2 :(得分:10)
typescript中的接口类似于C#中的接口,因为它们都提供了契约。但是,与仅包含方法的C#接口相反,typescript接口也可以描述对象包含的字段或属性。因此,它们也可以用于C#接口无法直接使用的东西。
typescript中的接口和类之间的主要区别在于接口没有运行时表示,并且不会为它们发出任何代码。接口非常广泛可用。例如,您可以使用对象文字来构造满足接口的对象。像:
let user: User = {
name: 'abc',
address: {
street: 'xyz',
},
};
或者您可以将任何数据对象(例如通过JSON解析接收)分配给接口(但您的预检查应断言它是真正有效的数据)。因此,接口对数据非常灵活。
另一方面,类具有在运行时与它们关联的类型,并且生成了代码。您可以使用instanceof
在运行时检查类型,并设置原型链。如果将User
定义为类,除非调用构造函数,否则它将不是有效用户。而且您不能将任何类型的合适数据定义为User
。您需要创建一个新实例并复制属性。
我个人的经验法则:
答案 3 :(得分:2)
如何在TypeScript中正确使用接口:建立行为契约,或者定义属性和对象应该有什么?
TypeScript中的接口是形状合约,描述了对象的预期结构。如果某个值具有某个接口注释,则您希望它是一个以接口中定义的成员为特征的对象。成员可以是价值观或职能(方法)。通常,他们的行为(职能机构)不是合同的一部分。但您可以指定它们是否为readonly
。
那么TypeScript中的接口是什么意思?为什么人们在TypeScript中使用接口,就像我们在C#中使用clases一样?
如果期望TypeScript类可以通过TypeScript类实现,那么它们可以扮演与C#接口相同的角色。
但不仅一个类可以实现一个接口;任何一种价值都可以:
interface HelloPrinter {
printHello(): void
}
以下对象不是类,但仍然实现了接口:
{
printHello: () => console.log("hello")
}
因此我们可以做到
const o: HelloPrinter = {
printHello: () => console.log("hello")
}
并且TypeScript编译器不会抱怨。
该对象实现了我们的接口,而没有强迫我们编写一个类。
使用接口比使用(接口和)类更轻量级。
但是如果你需要在运行时知道类型名称(类/接口名称),那么类是正确的选择,因为接口名称只在编译时才知道。
答案 4 :(得分:1)
仅使用本机反序列化机制,您无法反序列化特定类的实例。您只能反序列化为普通的javascript对象。这些对象可以遵循typescript接口,但不能是类的实例。如果需要处理跨越序列化边界的数据(例如Web服务期望的数据),请使用接口。如果你需要自己生成这些值的新实例,只需按字面构造它们或创建一个返回它们的便利函数 - 符合该接口的对象。
一个类本身可以实现一个接口,但如果你希望处理本地构造的类实例和反序列化的重构普通对象,它可能会让人感到困惑。你永远不能依赖于对象的类基础,所以没有把它定义为一个用于那个目的的类的好处。
我成功创建了一个ServerProxy模块,负责从webservice来回发送代码 - webservice调用和返回的结果。如果您要绑定到淘汰模型或类似模型,您可以使用一个类,该类使用构造函数封装ui-bound模型,该构造函数知道如何解除依赖于Web服务的返回的普通javascript对象' s interface with only与你的模型类的实例。