課題3: インターフェース (Interface) と 型エイリアス (Type Alias) (所要時間目安: 15‐25分) - hideki5123/myts GitHub Wiki

次は、オブジェクトの「形」を定義するための強力な方法である interface と、型に別名を付ける type エイリアスを学びましょう。

C#との比較:

  • interface:

    • TypeScript: オブジェクトが持つべきプロパティやメソッドの型を定義します。構造的部分型(Structural Typing)の原則に基づき、オブジェクトが必要なプロパティ/メソッドを(正しい型で)持っていれば、明示的に implements しなくてもインターフェースを満たしているとみなされます。主にオブジェクトの形状定義に使われます。コンパイル時にのみ存在し、ランタイムのJavaScriptコードには残りません。
    • C#: クラスが実装すべきメンバー(メソッド、プロパティ、イベントなど)のコントラクト(契約)を定義します。クラスはインターフェースを明示的に implements する必要があり、すべてのメンバーを実装しなければなりません。ランタイムにも型の情報として存在します。
    • 類似点: 特定の構造や契約を定義する点。
    • 相違点: TypeScriptは構造(アヒル)タイピング、C#は明示的な実装(ノミナルタイピング)。TypeScriptのInterfaceはコンパイル時のみ。
  • type エイリアス:

    • TypeScript: 既存の型(プリミティブ型、オブジェクト型、ユニオン型、タプル型など)に新しい名前(エイリアス)を付けます。複雑な型を再利用しやすくしたり、意図を明確にしたりするのに役立ちます。
    • C#: using ディレクティブを使った型エイリアス (using UserId = System.Int32;) に似ていますが、TypeScriptの type はより強力で、オブジェクトリテラル型、ユニオン型 (string | number)、交差型 (A & B) など、より複雑な型定義にも使えます。

課題内容:

  1. 新しいファイルの作成: src ディレクトリに interfaces.ts という新しいファイルを作成してください。

  2. インターフェースの定義と使用: interfaces.ts に以下のようなコードを書いてみてください。

    // src/interfaces.ts
    
    // ユーザー情報を表すインターフェース
    interface User {
      id: number;
      name: string;
      email?: string; // ? を付けるとオプショナル(任意)なプロパティになる
      readonly isActive: boolean; // readonly を付けると再代入不可になる
    }
    
    // Userインターフェースを満たすオブジェクトを作成
    const user1: User = {
      id: 1,
      name: "Hideki",
      // email: "[email protected]", // emailはオプショナルなので無くてもOK
      isActive: true,
    };
    
    // 読み取り専用プロパティへの再代入はエラーになる
    // user1.isActive = false; // この行のコメントを外すとエラー
    
    // オプショナルプロパティを持つオブジェクト
    const user2: User = {
      id: 2,
      name: "Alice",
      email: "[email protected]",
      isActive: false,
    };
    
    // インターフェースを型注釈として使う関数
    function printUser(user: User): void { // void は関数が何も返さないことを示す型 (C#のvoidと同じ)
      console.log(`ID: ${user.id}, Name: ${user.name}, Active: ${user.isActive}`);
      if (user.email) {
        console.log(`Email: ${user.email}`);
      }
    }
    
    console.log("Printing users:");
    printUser(user1);
    printUser(user2);
    
    // --- 型エイリアス ---
    
    // プリミティブ型のエイリアス
    type UserID = number;
    type UserName = string;
    
    // ユニオン型(複数の型のいずれかを表す)のエイリアス
    type StringOrNumber = string | number;
    
    let value1: StringOrNumber = "hello";
    let value2: StringOrNumber = 123;
    // let value3: StringOrNumber = true; // boolean型は許可されていないのでエラー
    
    // オブジェクト形状のエイリアス (interface と似た使い方もできる)
    type Point = {
      x: number;
      y: number;
    };
    
    const p1: Point = { x: 10, y: 20 };
    console.log(`\nPoint: (${p1.x}, ${p1.y})`);
    
    // interface と type の主な違いの一つ: interfaceは同名で宣言するとマージされるが、typeはできない
    
    interface Box {
        height: number;
        width: number;
    }
    interface Box {
        scale: number;
    }
    const box: Box = { height: 5, width: 6, scale: 10 }; // OK、マージされる
    
    /*
    type Window { // 同じ名前で type は再宣言できない(エラーになる)
        title: string;
    }
    type Window {
        ts: any;
    }
    */
    
  3. コンパイルと実行:

    • ターミナルで npx tsc を実行してコンパイルします。
    • node dist/interfaces.js を実行して結果を確認します。
    • エラーになる行のコメントを外して、コンパイル時に型エラーが検出されることを確認してください。
  4. コミットとPush:

    • src/interfaces.ts の変更をコミットし、GitHubにPushしてください (例: git commit -m "Add interfaces and type aliases examples" )。
    • 新しいコミットへのリンクを教えてください。

インターフェースはTypeScriptで非常に頻繁に使われる重要な機能です。type エイリアスもコードの可読性を高めるのに役立ちます。試してみてください!