为什么TypeScript在实现时允许重复组件?

时间:2017-11-15 12:46:37

标签: angular oop typescript inheritance ecmascript-5

为什么TypeScript在implements时允许重复组件?

import { Component,OnInit } from '@angular/core';

export class CreateVersionComponent implements OnInit, OnInit, OnInit { }// no error
export class CreateVersionComponent extends OnInit, OnInit, OnInit { }// getting error

但是当组件扩展时,它会抛出重复标识符错误

  

那么打字稿在实现时接受重复组件的原因是什么?我们需要使用哪种情况?

4 个答案:

答案 0 :(得分:7)

要理解为什么第一个代码不是问题,但第二个代码是,您需要了解类和接口之间的区别。接口是其实施者至少提供接口成员的保证。它不提供任何实际功能。但是一个类可以包含实现代码;您可以从类继承以重用该代码并通过添加新代码或更改现有实现来更改其行为。

这意味着implementsextends具有不同的含义。 implements说:我可以向这个类的每个消费者保证,它至少会有接口的成员。由于接口中没有实际的实现,因此只要该类实现了所有这些保证,就可以制作多个这些保证。你是对的,多次添加相同的保证没有任何意义,但它确实也不会受到伤害。 TypeScript的创建者可能被禁止多次实现该接口。我们可以推测他们为什么没有;我的猜测是,由于TypeScript基于JavaScript而且JS非常宽容,他们不想禁止不会造成任何损害的东西。请注意,TS是JS之上的类型层,并且在编译到JS期间最终会丢弃所有类型信息。在这种情况下,丢弃多个重复的接口实现并没有真正伤害,因为结果将完全相同。

implements以外,extends是另一回事。虽然有一些语言允许多重继承(例如C ++),但是多重继承伴随着许多困难的实现细节(例如diamond problem或调用基类构造函数),因此许多语言不支持它认为它会引起比它可能解决的问题更多的问题。 TypeScript不允许多重继承,这意味着在一般原则上不能将extends与多个基类一起使用。与实现接口不同,继承类会对程序的工作方式产生影响,编译器所做的不仅仅是剥离类型信息。这就是为什么在那里引发错误是有道理的。

答案 1 :(得分:3)

现有的答案很好地解释了:

  • Class vs. interface。
  • 多重继承与实现多个接口。
  • 通过编译擦除接口意味着编译的代码与implements子句中的冗余接口没有区别。

然而仍有一些混乱。从另一个角度来看问题:

  

我们需要使用哪种情况?

你不是。您无需声明冗余接口。它让我想起这样的事情:

var v = v = v = 66

,就编译器而言,它很好。 ,您不需要这样做。

  

为什么接受?

很容易理解为什么有人(特别是有Java背景的人)可能因缺少警告而感到困惑。毕竟,Eclipse多年来一直警告我这件事(你好,Serializable!)。

在单个类定义中多次命名相同的接口有点奇怪。考虑更可能实际发生的冗余接口示例可能会有所帮助:

interface StringProducer {
    getString: () => string;
}

class Parent implements StringProducer {
    getString =  function(): string {
        return 'x';
    }
}

class Child extends Parent implements StringProducer {
    getString = function() : string {
        return 'y';
    }
}

class GrandChild extends Child implements StringProducer {
    getString = function(): string {
        return 'z';
    }
}

console.log(new Parent().getString());
console.log(new Child().getString());
console.log(new GrandChild().getString());

你可以(松散地)想到这样的GrandChild类:

public class GrandChild implements StringProducer, StringProducer, StringProducer {

因为一个类实现了它的所有接口及其祖先的接口。

编译器(或者linter)是否应该对此嗤之以鼻?我应该强制implementsChild删除GrandChild条款吗?

我认为这主要是一个偏好问题。例如,当我在IDE中打开GrandChild时,我可能希望在该文件中看到该类实现的所有接口。另一方面,我可能觉得这只是噪音,需要警告。

编译器当然不关心,也不需要。但是我可以看到为什么你可能想要一个lint警告。在一天结束时的问题似乎(对我来说)是"为什么没有冗余接口的tslint规则?"。这是一个合理的问题,我无法回答。 You could always write such a rule并与我们其他人分享。

答案 2 :(得分:1)

TypeScript不允许多重继承,就像Java,C#等。所以第二个例子不会先工作,因为TSC认为你试图扩展多个类,因为它是同一个类失败。

对于第一种情况,我同意它应该说些什么,因为它可能是一个小错误。另一方面,它在语义上不是错误的。当你在第一个OnInit中实现方法时,你也会为第二个和第三个实现它,所以你应该被覆盖。

答案 3 :(得分:1)

答案很简单。

Typescript不允许多重继承

这意味着,一个类不能从多个类继承。 (这是'延伸')。

现在让我们来'实施'

在这种情况下,我们谈论的是接口。您可以实现所需的多个接口。

请记住,实现接口并不意味着继承。它只是意味着您在类上实现了不同的模型,您的类定义必须遵守这些模型

因此,扩展错误(由于多重继承,这是不允许的) 实现没有错误(由于允许多个接口实现)