TypeScriptの「拡張」と「実装」の違いは何ですか


回答:


153

短縮版

  • extends 手段:

新しいクラスが子です。継承に伴うメリットがあります。親としてすべてのプロパティ、メソッドがあります。これらのいくつかをオーバーライドして新しいものを実装できますが、親のものはすでに含まれています。

  • implements 手段:

新しいクラスは、として扱うことができ、同じ「形」が、それは子供ではありません。とはPerson異なる親を持つかどうかに関係なく、が必要な任意のメソッドに渡すことができますPerson

もっと ...

ではOOP (C#、Javaなどの言語)私たちが使用します

extends継承から利益を得るため(wikiを参照)。小さい引用:

...ほとんどのクラスベースのオブジェクト指向言語の継承は、1つのオブジェクトが親オブジェクトのすべてのプロパティと動作を取得するメカニズムです。継承により、プログラマは次のことができます。既存のクラスに基づいて構築されるクラスを作成する...

implementsポリモーフィズムについてはさらに詳しくなりますwikiを参照)。小さい引用:

...ポリモーフィズムは、さまざまなタイプのエンティティへの単一のインターフェースの提供です...

したがって、の本当に異なる継承ツリーを持つことができますclass Man

class Man extends Human ...

しかし、別のタイプのふりをすることもできると宣言した場合- Person

class Man extends Human 
          implements Person ...

.. Person必要な場所ならどこでも使用できます。Personsを"interface" 実行する(つまり、すべてのパブリックなものを実装する)必要があります。

implement他のクラス?それは本当にクールなものです

Javascriptの良い面(利点の1つ)は、Duckタイピングの組み込みサポートです(wikiを参照)。小さい引用:

「それがアヒルのように歩き、それがアヒルのようにガクガク音を立てるなら、それはアヒルでなければならない。」

したがって、JavaScriptでは、2つの異なるオブジェクトに1つの類似したメソッド(たとえばrender())がある場合、それらを期待する関数に渡すことができます。

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

それを失わないために-Typescriptでも同じことができます-より多くの型付きサポートが必要です。そしてそれが

class implements class

それが意味をなす場合、その役割があります

OOP言語ではC#...それを行う方法はありません...

また、ドキュメントはここで役立つはずです:

クラスを拡張するインターフェース

インターフェース型がクラス型を拡張するとき、それはクラスのメンバーを継承しますが、それらの実装は継承しません。インターフェースが実装を提供せずにクラスのすべてのメンバーを宣言したかのようです。インターフェイスは、基本クラスのプライベートおよび保護されたメンバーも継承します。つまり、プライベートまたは保護されたメンバーでクラスを拡張するインターフェースを作成する場合、そのインターフェースタイプは、そのクラスまたはそのサブクラスでのみ実装できます。

これは、継承階層が大きいが、コードが特定のプロパティを持つサブクラスのみで機能するように指定する場合に役立ちます。サブクラスは、基本クラスからの継承以外に関連している必要はありません。例えば:

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親からすべて取得する」と言った場合、プライベートメンバーに適用されますか?例えばclass Person {private name: string} class man extends Person{gender: string;}ないmanプロパティ名を持っていますか?
davejoem

プライベートもあります。TSからアクセスできません。それらを保護し、使用できるようにします。「実装」の場合、パブリック部分だけが理にかなっています。少しお役に立てば
幸い

すばらしい答えです。「プライベートはありますが、TSからはアクセスできません」に対するコメントではわかりません。新しく作成された子オブジェクトにプライベートプロパティがコピーされるということですか?実装の場合、パブリックプロパティのみがコピーされますか?
kushalvm

また、もう一点得ました。これが拡張の定義である場合。次に、このstackoverflow.com/questions/60390454/…
kushalvm

96

typescript(およびその他のオブジェクト指向言語)には、クラスとインターフェースがあります。

インターフェイスには実装がなく、この型が持つメンバー/メソッドの「契約」にすぎません。
例えば:

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

このPointインターフェイスを実装するインスタンスには、型番号の2つのメンバーが必要です:xydistance別のPointインスタンスを受け取ってを返す1つのメソッド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));
    }
}

遊び場のコード

あなたの例ではPerson、クラスを拡張するときにクラスとして1回、実装するときにインターフェイスとして1回扱います。
あなたのコード:

class Person {
    name: string;
    age: number;
}
class Child  extends Person {}

class Man implements Person {}

言うコンパイルエラーがあります:

クラス「Man」は、インターフェース「Person」を正しく実装していません。
タイプ 'Man'にプロパティ 'name'がありません。

そしてそれはインターフェースが実装を欠いているからです。
したがってimplement、クラスの場合は、実装せずにその「契約」だけを取るので、これを行う必要があります。

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

遊び場のコード

要するに、ほとんどの場合、extend別のクラスではなく、implementそれを望んでいるということです。


7
この答えは理解しやすいです。
Akshay Raut

6

@ nitzan-tomerからのすばらしい回答!私を大いに助けました...私は彼のデモを少し拡張しました:

IPoint interface;
Point implements IPoint;
Point3D extends Point;

そして、IPoint型を期待する関数でどのように動作するか。

だから私がこれまでに学んだことと経験則として使用していること:ジェネリック型を期待するクラスとメソッドを使用している場合、期待される型としてインターフェイスを使用します。また、親または基本クラスがそのインターフェイスを使用していることを確認してください。そうすれば、インターフェースを実装する限り、それらのすべてのサブクラスを使用できます。

ここで拡張デモ


これは質問に対する答えを提供しません。批評したり、著者に説明を求めたりするには、投稿の下にコメントを残してください。- レビューから
aronisstav 2018

1
@aronisstav私は、すでに私に役立つ良い答えを見つけたものの拡張デモを投稿しただけです。しかし、多分他の誰かが私がデモを拡張した作業が役に立つと思うでしょう。それで全部です。コメントはコードブロックを配置するためのものではありません。そのため、私はアンサーポストでより理解しやすいと思います。それでそれの問題は何ですか?
アンゼップ2018

あなたの回答は、長さと内容により(自動的に?)その主な貢献(デモを拡張したことを説明)は、コメントとしてより良いでしょう。追加された段落を使用すると、おそらくそれは実際により便利です。
aronisstav 2018

@andzepあなたの拡張されたデモの例は本当に役に立ちます。
18年

3
  1. インターフェースは形状とのインターフェースを拡張します
  2. インターフェースは形状でクラスを拡張します
  3. クラスの実装インターフェイスは、インターフェイスによって提供されるすべてのフィールドを実装する必要があります
  4. クラスは形状を持つクラスを実装します
  5. クラスはすべてのフィールドでクラスを拡張します

extends継承にimplements重点を置き、インターフェイスまたはクラスの制約に重点を置きます。


0

VS実装を拡張

  • extends:子クラス(拡張)は、クラスのすべてのプロパティとメソッドを継承します。
  • implementsimplementsキーワードを使用するクラスは、そのクラスのすべてのプロパティとメソッドを実装する必要があります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自体からすべてを実装する必要があることがわかります。

たとえばwalkメソッドなど、manクラスから何かを削除すると、次のコンパイル時エラーが発生します。

クラス 'man'は、クラス 'Person'を誤って実装します。「Person」を拡張して、そのメンバーをサブクラスとして継承するつもりですか?タイプ「man」にはプロパティ「walk」がありませんが、タイプ「Person」では必須です。(2720)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.