次のタイプが定義されているとしましょう:
interface Shape {
color: string;
}
ここで、このタイプにプロパティを追加する次の方法を検討してください。
拡張子
interface Square extends Shape {
sideLength: number;
}
交差点
type Square = Shape & {
sideLength: number;
}
両方のアプローチの違いは何ですか?
そして、完全性と好奇心のために、同等の結果をもたらす他の方法はありますか?
はい、あなたのシナリオに関係があるかもしれないし、そうでないかもしれない違いがあります。
おそらく最も重要なのは、同じプロパティキーを持つメンバーが両方のタイプに存在する場合の処理方法の違いです。
考慮してください:
interface NumberToStringConverter {
convert: (value: number) => string;
}
interface BidirectionalStringNumberConverter extends NumberToStringConverter {
convert: (value: string) => number;
}
上記のextends
はエラーになります。これは、派生インターフェイスが、派生インターフェイスと同じキーを持つが、互換性のない署名を持つプロパティを宣言するためです。
error TS2430: Interface 'BidirectionalStringNumberConverter' incorrectly extends interface 'NumberToStringConverter'.
Types of property 'convert' are incompatible.
Type '(value: string) => number' is not assignable to type '(value: number) => string'.
Types of parameters 'value' and 'value' are incompatible.
Type 'number' is not assignable to type 'string'.
ただし、交差点タイプを使用する場合
interface NumberToStringConverter = {
convert: (value: number) => string;
}
type BidirectionalStringNumberConverter = NumberToStringConverter & {
convert: (value: string) => number;
}
エラーは一切なく、さらに与えられます
declare const converter: BidirectionalStringNumberConverter;
converter.convert(0); // `convert`'s call signature comes from `NumberToStringConverter`
converter.convert('a'); // `convert`'s call signature comes from `BidirectionalStringNumberConverter`
// And this is a good thing indeed as a value conforming to the type is easily conceived
const converter: BidirectionalStringNumberConverter = {
convert: (value: string | number) =>
typeof value === 'string'
? Number(value)
: String(value)
}
これは別の興味深い違いにつながります。interface
宣言は無制限です。同じ宣言スペースにあり、同じ名前を持つinterface
宣言はmergedであるため、新しいメンバーはどこにでも追加できます。
動作をマージする一般的な使用方法は次のとおりです
lib.d.ts
interface Array<T> {
// map, filter, etc.
}
array-flat-map-polyfill.ts
interface Array<T> {
flatMap<R>(f: (x: T) => R[]): R[];
}
if (typeof Array.prototype.flatMap !== 'function') {
Array.prototype.flatMap = function (f) {
return this.map(f).reduce((xs, ys) => [...xs, ...ys], []);
}
}
extends
句が存在しないことに注意してください。個別のファイルで指定されている場合でも、インターフェイスは両方ともグローバルスコープにあり、名前によって両方のメンバーセットを持つ単一の論理インターフェイス宣言にマージされます。 (同じことが、わずかに異なる構文を持つモジュールスコープ宣言に対しても実行できます)
対照的に、type
宣言に格納されている交差タイプは閉じられており、マージの対象ではありません。
たくさんの違いがあります。 TypeScriptハンドブックで両方の構成について詳しく読むことができます。 Interfaces および Advanced Types セクションは特に関連があります。