TypeScript中的接口和类

时间:2016-11-14 14:44:35

标签: javascript typescript interface

在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中正确使用接口:建立行为契约,或者定义属性和对象应该有什么?

5 个答案:

答案 0 :(得分:25)

考虑到在Javascript中,数据通常通过JSON交换为普通对象:

let data = JSON.parse(someString);

假设这个dataUser个对象的数组,我们会将它传递给函数:

data.forEach(user => foo(user))

foo的输入方式如下:

function foo(user: User) { ... }

但等等,我们没有做new User!我们应该吗?我们是否必须将Usermap所有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;
}());

Try it out

答案 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与你的模型类的实例。