演習 - TypeScript でインターフェイスを拡張する
インターフェイスは相互に拡張できます。 これにより、あるインターフェイスのメンバーを別のインターフェイスにコピーできます。そのため、インターフェイスを再利用可能なコンポーネントに切り分ける方法がより柔軟になります。
インターフェイスを 1 つ以上のインターフェイスに拡張する場合、次の規則が適用されます。
- すべてのインターフェイスのすべての必須プロパティを実装する必要があります。
- プロパティの名前と型がまったく同じである場合、2 つのインターフェイスは同じプロパティを持つことができます。
- 2 つのインターフェイスに同じ名前で型が異なるプロパティがある場合は、両方のインターフェイスのサブタイプであるプロパティになるように、新しいプロパティを宣言する必要があります。
インターフェイスを拡張する
IceCream
インターフェイスから作成できるデザートにはいくつかの種類 (サンデー、ミルクシェイクなど) がありますが、それらすべてに、IceCream
で宣言したもの以外の異なる追加のプロパティがあります。 Sundae
という新しい 1 つのインターフェイスを使用してインターフェイスを拡張し、そのプロパティを宣言してみましょう。
プレイグラウンドでプロジェクトを続行します。
IceCream
インターフェイス宣言の下にSundae
という新しいインターフェイスを宣言し、IceCream
インターフェイスをextends
します。Sundae
インターフェイスには 4 つの新しいプロパティが含まれています。- リテラル型の
'chocolate' | 'caramel' | 'strawberry'
であるsauce
boolean
型のnuts
(省略可能)boolean
型のwhippedCream
(省略可能)boolean
型のinstructions
(省略可能)
interface Sundae extends IceCream { sauce: 'chocolate' | 'caramel' | 'strawberry'; nuts?: boolean; whippedCream?: boolean; instructions?: boolean; }
- リテラル型の
新しいインターフェイスにエラーが表示されるのがわかります。 TypeScript で、
IceCream
とSundae
の両方のインターフェイスにinstructions
というプロパティがあるものの、それらの型が異なることが検出されました。 このエラーを解決するために、両方のinstructions
プロパティを同じ型string
にしましょう。myIceCream
変数をSundae
型に変更して新しいインターフェイスを試してみます。 すると、"Property 'sauce' is missing in type '{ flavor: string; scoops: number; }' but required in type 'Sundae'" (プロパティ 'sauce' が型 '{ flavor: string; scoops: number; }' にありませんが、型 'Sundae' で必須です) というエラーが生成されます。 Sundae インターフェイスに 4 つの新しいプロパティを追加しましたが、sauce プロパティのみが必須でした。let myIceCream: Sundae = { flavor: 'vanilla', scoops: 2 }
その必須プロパティと、使用する省略可能なプロパティのうち任意のどれかを追加して、エラーを修正します。
let myIceCream: Sundae = { flavor: 'vanilla', scoops: 2, sauce: 'caramel', nuts: true }
次に、
Sundae
インターフェイスをtooManyScoops
関数で実装します。 関数自体にエラーは表示されませんが、次の行の関数呼び出しでエラーが生成されます。 これは、3 つの必須パラメーターが想定されているためです。 エラーを修正するには、sauce
プロパティを関数呼び出しに追加します。function tooManyScoops(dessert: Sundae) { if (dessert.scoops >= 4) { return dessert.scoops + ' is too many scoops!'; } else { return 'Your order will be ready soon!'; } } console.log(tooManyScoops({flavor: 'vanilla', scoops: 5, sauce: 'caramel'}));