TypeScript 中的“扩展”和“实现”有啥区别

Posted

技术标签:

【中文标题】TypeScript 中的“扩展”和“实现”有啥区别【英文标题】:What's the difference between 'extends' and 'implements' in TypeScriptTypeScript 中的“扩展”和“实现”有什么区别 【发布时间】:2016-12-14 13:09:55 【问题描述】:

我想知道 ManChild 的共同点和区别。 p>

class Person 
  name: string;
  age: number;

class Child extends Person 
class Man implements Person 

【问题讨论】:

这里很好解释:***.com/a/35990799/452213。特别是示例:typescriptlang.org/play/… 【参考方案1】:

短版

extends 表示:

新班级是一个孩子。它得到继承带来的好处。它具有作为其父级的所有属性、方法。它可以覆盖其中的一些并实现新的,但已经包含了父级的东西。

implements 表示:

新类可以被视为相同的“形状”,而它不是子类 .它可以传递给任何需要Person 的方法,无论其父对象是否与Person 不同

更多...

在OOP (C#、Java 等语言)我们会使用

extends 从继承中获利(参见wiki)。小引:

... 在大多数基于类的面向对象语言中,继承是一种机制,其中一个对象获取父对象的所有属性和行为。继承允许程序员:创建基于现有类的类...

implements 将更多地用于多态性(参见wiki)。小引:

...多态性是为不同类型的实体提供单一接口...

所以,我们的class Man 可以拥有完全不同的继承树。

class Man extends Human ...

但如果我们也声明我们可以伪装成不同的类型 - Person:

class Man extends Human 
          implements Person ...

.. 那么我们可以在任何需要Person 的地方使用它。我们只需要完成 Persons 的 "interface"(即实现其所有公共内容)

implement其他班级?这真是很酷的东西

javascript 的漂亮外观(其中一个好处) 是对 Duck 类型 (see wiki) 的内置支持。小引:

“如果它走路像鸭子,叫起来像鸭子,那它一定是鸭子。”

因此,在 Javascript 中,如果两个不同的对象...会有一个相似的方法(例如 render(),它们可以传递给期望它的函数:

function(engine)
  engine.render() // any type implementing render() can be passed

为了不失去这一点——我们可以在 Typescript 中做同样的事情——提供更多类型的支持。这就是

class implements class

有它的作用,它是有意义的

在 OOP 语言中,C# ... 没办法做到这一点...

这里的文档也应该有所帮助:

Interfaces Extending Classes

当一个接口类型扩展一个类类型时,它会继承其成员 类,但不是他们的实现。好像界面有 声明了类的所有成员而不提供 执行。接口甚至继承私有和受保护的 基类的成员。这意味着当你创建一个接口时 扩展具有私有或受保护成员的类,该接口 type 只能由该类或其子类实现。

当你有一个大的继承层次结构时,这很有用,但是想要 指定您的代码仅适用于具有特定 特性。除了继承之外,子类不必相关 从基类。例如:

class Control 
    private state: any;


interface SelectableControl extends Control 
    select(): void;


class Button extends Control implements SelectableControl 
    select()  


class TextBox extends Control 
    select()  


// Error: Property 'state' is missing in type 'Image'.
class Image implements SelectableControl 
    private state: any;
    select()  


class Location 


所以,虽然

extends 表示 - 它从其父级获取所有内容 implements 在这种情况下几乎就像实现一个接口。子对象可以假装它是父对象......但它没有得到任何实现

【讨论】:

当你说“extends-it get all from its parent”时,它是否适用于私人成员?例如class Person private name: string class man extends Persongender: string; man 有属性名称吗? 私人也有。 TS无法访问。使它们受到保护,您就可以使用它们。在“实施”的情况下,只有公共部分才有意义。希望对你有帮助 优秀的答案。只是不确定您对“私人存在但 TS 无法访问”的评论。您的意思是私有属性被复制到新创建的子对象中吗?而在实现的情况下,只复制公共属性? 另外,我又得到了一点。如果这是扩展的定义。那么请你解释一下***.com/questions/60390454/… Image 的实际错误更清楚。 “类 'Image' 错误地实现了接口 SelectableControl。类型具有私有属性 'state' 的单独声明。”说,“财产状态丢失”是令人困惑的,因为它没有丢失,它是重复的。【参考方案2】:

在 typescript(和其他一些 OO 语言)中,您有类和接口。

接口没有实现,它只是该类型所具有的成员/方法的“契约”。 例如:

interface Point 
    x: number;
    y: number;
    distance(other: Point): number;

实现这个Point接口的实例必须有两个类型编号的成员:xy,一个方法distance接收另一个Point实例并返回一个number。 该接口没有实现任何这些。

类是实现:

class PointImplementation implements Point 
    public x: number;
    public y: number;

    constructor(x: number, y: number) 
        this.x = x;
        this.y = y;
    

    public distance(other: Point): number 
        return Math.sqrt(Math.pow(this.x - other.x, 2) + Math.pow(this.y - other.y, 2));
    

(code in playground)

在您的示例中,您在扩展 Person 类时将其视为类,在实现时将其视为接口。 你的代码:

class Person 
    name: string;
    age: number;

class Child  extends Person 

class Man implements Person 

有一个编译错误说:

“Man”类错误地实现了“Person”接口。 “人”类型中缺少属性“名称”。

那是因为接口缺乏实现。 所以如果你 implement 一个类,那么你只接受它的“合同”而没有实现,所以你需要这样做:

class NoErrorMan implements Person 
    name: string;
    age: number;

(code in playground)

底线是,在大多数情况下,您想要extend 另一个类而不是implement 它。

【讨论】:

【参考方案3】:

扩展 VS 实现

extends: 子类(被扩展)将继承类的所有属性和方法被扩展 implements:使用implements 关键字的类需要实现implements 的类的所有属性和方法

简单来说:

extends: 在这里你可以从父类中获取所有这些方法/属性,所以你不必自己实现这个 implements:这是班级必须遵守的合同。该类必须实现至少以下方法/属性

示例:

class Person 
  name: string;
  age: number;

  walk(): void 
    console.log('Walking (person Class)')
  

  constructor(name: string, age: number) 
    this.name = name;
    this.age = age;
  

class child extends Person  

// Man has to implements at least all the properties
// and methods of the Person class
class man implements Person 
  name: string;
  age: number

  constructor(name: string, age: number) 
    this.name = name;
    this.age = age;
  

  walk(): void 
    console.log('Walking (man class)')
  



(new child('Mike', 12)).walk();
// logs: Walking(person Class)

(new man('Tom', 12)).walk();
// logs: Walking(man class)

在示例中,我们可以观察到子类继承了 Person 的所有内容,而 man 类必须实现 Person 本身的所有内容。

如果我们要从 man 类中删除一些东西,例如 walk 方法,我们会得到以下 compile time 错误:

“man”类错误地实现了“Person”类。你的意思是 扩展“人”并将其成员作为子类继承?财产 “man”类型中缺少“walk”,但在“Person”类型中是必需的。(2720)

【讨论】:

完美解释【参考方案4】:

来自@nitzan-tomer 的好答案!帮了我很多...我扩展了他的演示:

IPoint interface;
Point implements IPoint;
Point3D extends Point;

以及它们在期望 IPoint 类型的函数中的行为。

到目前为止,我所学到的并被用作经验法则​​:如果您正在使用期望泛型类型的类和方法,请使用接口作为期望的类型。并确保父类或基类使用该接口。这样你就可以使用那些实现接口的所有子类。

这里是extended demo

【讨论】:

这并没有提供问题的答案。要批评或要求作者澄清,请在他们的帖子下方留下评论。 - From Review @aronisstav 我只发布了一个扩展演示,说明我找到了一个对我有帮助的好答案。但也许其他人会发现我所做的扩展演示的工作很有用。就这样。评论并不是真的用来放置代码块,所以这就是为什么我发现它在 Answer-Post 中更容易理解。那么它有什么问题呢? 您的答案(自动?)由于长度和内容而被标记,出现在我的审核队列中,我对标记中提出的原因给予了评价。它的主要贡献(解释你扩展了演示)作为评论会更好。加上添加的段落,也许它确实更有用。 @andzep 你的扩展演示示例真的很有帮助。【参考方案5】:
    接口扩展接口与形状 接口扩展类与形状 类实现接口应该实现接口提供的所有字段 类实现具有形状的类 类扩展了包含所有字段的类

extends 专注于继承,implements 专注于约束,无论是接口还是类。

【讨论】:

【参考方案6】:

基本上:

extends 将获取父类的所有属性和方法。 implements 将要求我们实现接口中定义的所有属性和方法。

【讨论】:

以上是关于TypeScript 中的“扩展”和“实现”有啥区别的主要内容,如果未能解决你的问题,请参考以下文章

Java 中 给一个object 赋值属性, 既可以用构造函数的方式,也可以用setXXXX()的方式,而它们之间有啥区

TypeScript 对象定义中的 '!:' 和 '?:' 有啥区别?

TypeScript 中的 function 和 => 有啥区别? [复制]

TypeScript 中的“声明类”和“接口”有啥区别

TypeScript 中的 Import 和 require 有啥不同?

Typescript中的接口和抽象类有啥区别?