web-dev-qa-db-ja.com

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

manchild共通点があり、どのように異なるか。

class Person {
  name: string;
  age: number;
}
class child extends Person {}
class man implements Person {}
62
davejoem

短縮版

  • extends意味:

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

  • implements意味:

新しいクラスは、同じ "shape"それは子ではありません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 Nice face(利点の1つ)は、ダックタイピングの組み込みサポートです( wikiを参照 )。小さな引用:

「それがアヒルのように歩き、それがアヒルのように鳴るなら、それはアヒルでなければなりません。」

そのため、Javascriptでは、2つの異なるオブジェクト...に1つの類似したメソッド(e.g。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 {
    select() { }
}

class TextBox extends Control {
    select() { }
}

class Image extends Control {
}

class Location {
    select() { }
}

それで、

  • extendsは、すべてを親から取得することを意味します
  • この場合のimplementsは、インターフェイスの実装に似ています。子オブジェクトは、親であるふりをすることができます...しかし、それは実装を取得しません
76
Radim Köhler

TypeScript(およびその他のOO言語)には、クラスとインターフェイスがあります。

インターフェースには実装がありません。これは、このタイプのメンバー/メソッドの「契約」にすぎません。
例えば:

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

このPointインターフェースを実装するインスタンスには、タイプ番号の2つのメンバー:xおよびyと、別のdistanceインスタンスを受け取り、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別のクラスにしたいということです。

63
Nitzan Tomer

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

IPoint interface;
Point implements IPoint;
Point3D extends Point;

そして、IPoint型を期待する関数での動作。

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

拡張デモ

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

extendsは継承に焦点を当て、implementsはインターフェイスまたはクラスに関係なく制約に焦点を当てます。

1
lei li