TypeScriptの「クラスを宣言する」と「インターフェース」の違いは何ですか


116

TypeScriptで.d.tsソース宣言ファイルを作成するとき、どちらが望ましいのですか?それはなぜですか?

declare class Example {
    public Method(): void; 
}

または

interface Example {
    Method(): void;
}

私が知ることができる違いは、インターフェイスには静的メソッドがないため、そのためにクラスを使用する必要があるということです。どちらもJS出力を生成しないので、おそらくそれは問題ではありませんか?



これらはどちらもJS出力なしで同じことを達成できるので、どちらを使用してもどちらを使用するかを説明するのに本当に役立つとは思いません。
Chris

1
Short:declareを使用して、実行時にクラスの実装が存在することを確認する必要がありますが、インターフェースでは必要ありません。
ハキム

回答:


163

interfaceオブジェクトの形状を簡単に説明する場合に使用します。インターフェースのコード生成はこれまでありません。それらは型システムの単なる成果物です。implements句があるかどうかによって、クラスのコード生成に違いはありません。

declare class外部に存在する既存のクラス(通常はTypeScriptクラスですが、常にではない)を記述したい場合に使用します(たとえば、2つの.tsファイルが2つの.jsファイルにコンパイルされ、両方がscriptタグを介して含まれている場合)ウェブページ)。classusing から継承した場合extends(基本型がdeclare classか通常かに関係なくclass)、コンパイラーはすべてのコードを生成して、プロトタイプチェーンと転送コンストラクターを接続します。

declare classインターフェイスであるはずだったから継承しようとすると、生成されたコードがランタイムマニフェストのないオブジェクトを参照するため、ランタイムエラーが発生します。

逆に、implement本来あるべきインターフェイスであるdeclare class場合は、すべてのメンバーを自分で再実装する必要があり、ベースクラスとなる可能性のあるコードから再利用されるコードや関数を利用することはありません。実行時にプロトタイプチェーンをチェックすると、実際には基本クラスのインスタンスではないため、オブジェクトが拒否されます。

あなたがC ++バックグラウンドを持っている場合は、本当にオタク取得するには、おおよその考えることができるinterfaceようtypedefdeclare classとしてextern厳密には、このコンパイル単位で定義を欠いていること、コンストラクタの宣言。

純粋な消費側(命令型コードを記述し、新しい型を追加しない)からすると、interfaceとの唯一の違いdeclare classnew、インターフェイスを使用できないことです。あなたがしようとする場合は、extend/ implement新しいでこれらのタイプのいずれかclass、あなたは絶対に間を正しく選択しているしなければならないinterfacedeclare class。そのうちの1つだけが機能します。

あなたに役立つ2つのルール:

  • 型の名前は、new実行時に実際に存在する(たとえばDate、そうでJQueryStaticはないが)コンストラクター関数(で呼び出すことができるもの)に対応していますか?いいえの場合、間違いなくinterface
  • 別のTypeScriptファイルからコンパイルされたクラス、または十分に類似したものを扱っていますか?はいの場合は、declare class

あなたは実際にtypescriptでインターフェースを新しくすることができます。唯一の制限は継承です。
Oleg Mihailik 2013年

3
newインターフェース・タイプに対してオペレーターを呼び出すことはできません。ただし、インターフェースは構成シグニチャーを持つことができnewます。つまり、インターフェース・タイプの値に対してオペレーターを呼び出すことができます。これはclass、構成シグニチャがその型の式ではなく型名自体にある場合の動作とは大きく異なります。
Ryan Cavanaugh 2013年

コンストラクタをインターフェースに追加する方法をとる場合、それはクラスの「静的」を除いて、インターフェースの唯一のメンバーでなければなりません。コンストラクター関数のインターフェースを、構築されたオブジェクトのインターフェースと組み合わせないでください。もしそうなら、型システムは次のような愚かさを許します:new(new x())、ここでx:インターフェース。
Jeremy Bell

24

次のインターフェースを実装できます。

class MyClass implements Example {
    Method() {

    }
}

一方、このdeclare class構文は、TypeScriptで記述されていない外部コードの型定義を追加するために実際に使用することを目的としているため、実装は「他の場所」にあります。


TypeScriptで記述されていないコードを記述するために宣言クラスを使用する必要があることを示唆していますか?私はそのような場合を想定しますが、チェックインしたjquery.d.tsファイルで、JQueryStaticはによって実装インタフェースです:宣言のvar $:これは宣言クラス$ {パブリック静的...}するのにJQueryStatic私が持っているだろうが
クリス

私がこれについて考えることができる唯一の理由は、あなたが人々にクラスを拡張させたくない場合でしょう-インターフェースを使用することは、実装全体を提供しなければならないことを意味します。
フェントン

理にかなっています。おそらくそれが理由でした。
Chris

それでは、別のJSライブラリの宣言をポイントしようとしているので、必ず宣言する必要があります。一部のライブラリ関数(クラス)でコードが静的を使用しています。これまでのところ、宣言ファイルで表現されている静的プロパティまたはメソッドはまだ見ていません。ああ、私は名前空間またはモジュールを使用する必要がありますか?
jenson-button-event

13

簡単に言えば、/ ファイルでdeclare使用され、現在のファイルで定義されていなくても、キーワードがその環境に存在することを期待する必要があることをコンパイラに伝えます。これにより、宣言されたオブジェクトを使用するときに型の安全性を確保できるようになります。Typescriptコンパイラは、他のコンポーネントがその変数を提供できることを認識しているためです。.tsd.tsdeclaring


6

TS declareとの違いinterface

宣言:

declare class Example {
    public Method(): void; 
}

上記のコードdeclareでは、クラスExampleが宣言されているどこかでTSコンパイラに通知します。これは、クラスが魔法のように含まれているという意味ではありません。プログラマとしてのあなたは、(declareキーワードで)宣言するときにクラスを利用可能にする責任があります。

インターフェース:

interface Example {
    Method(): void;
}

アンはinterface唯一typescriptです内に存在する仮想構成です。typescriptコンパイラは、型チェックの唯一の目的でそれを使用します。コードがJavaScriptにコンパイルされると、この構造全体が取り除かれます。typescriptコンパイラは、オブジェクトが正しい構造を持っているかどうかをチェックするためにインターフェースを使用します。

たとえば、次のインターフェイスがあるとします。

interface test {
  foo: number,
  bar: string,
}

このインターフェイスタイプを持つオブジェクトを定義すると、インターフェイスと完全に一致する必要があります。

// perfect match has all the properties with the right types, TS compiler will not complain.
  const obj1: test = {   
    foo: 5,
    bar: 'hey',
  }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.