演習 - TypeScript でインターフェイスを拡張する

完了

インターフェイスは相互に拡張できます。 これにより、あるインターフェイスのメンバーを別のインターフェイスにコピーできます。そのため、インターフェイスを再利用可能なコンポーネントに切り分ける方法がより柔軟になります。

インターフェイスを 1 つ以上のインターフェイスに拡張する場合、次の規則が適用されます。

  • すべてのインターフェイスのすべての必須プロパティを実装する必要があります。
  • プロパティの名前と型がまったく同じである場合、2 つのインターフェイスは同じプロパティを持つことができます。
  • 2 つのインターフェイスに同じ名前で型が異なるプロパティがある場合は、両方のインターフェイスのサブタイプであるプロパティになるように、新しいプロパティを宣言する必要があります。

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

IceCream インターフェイスから作成できるデザートにはいくつかの種類 (サンデー、ミルクシェイクなど) がありますが、それらすべてに、IceCream で宣言したもの以外の異なる追加のプロパティがあります。 Sundae という新しい 1 つのインターフェイスを使用してインターフェイスを拡張し、そのプロパティを宣言してみましょう。

  1. プレイグラウンドでプロジェクトを続行します。

  2. 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;
    }
    
  3. 新しいインターフェイスにエラーが表示されるのがわかります。 TypeScript で、IceCreamSundae の両方のインターフェイスに instructions というプロパティがあるものの、それらの型が異なることが検出されました。 このエラーを解決するために、両方の instructions プロパティを同じ型 string にしましょう。

  4. 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
    }
    
  5. その必須プロパティと、使用する省略可能なプロパティのうち任意のどれかを追加して、エラーを修正します。

    let myIceCream: Sundae = {
        flavor: 'vanilla',
        scoops: 2,
        sauce: 'caramel',
        nuts: true
    }
    
  6. 次に、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'}));