課題4: TypeScriptの関数 (発展) (所要時間目安: 20‐30分) - hideki5123/myts GitHub Wiki

次は、TypeScriptの関数について、もう少し掘り下げてみましょう。関数自体の型定義や、多様なパラメータの扱い方を見ていきます。

C#との比較:

  • 関数型エイリアス (type FuncType = ...):
    • TypeScript: 関数のシグネチャ(引数の型と戻り値の型)を type エイリアスで定義できます。例: type MathOperation = (x: number, y: number) => number;
    • C#: C#の delegate キーワード (delegate int MathOperation(int x, int y);) や、より一般的には System.FuncSystem.Action デリゲート (Func<int, int, int>) に相当します。どちらも関数の型シグネチャを定義する方法です。
  • オプショナルパラメータ (param?: type):
    • TypeScript: パラメータ名の後ろに ? を付けると、そのパラメータが省略可能になります。オプショナルパラメータは必須パラメータの後ろに置く必要があります。例: function greet(name: string, title?: string)
    • C#: C# 4.0以降のオプショナル引数と非常に似ています。C#では型名の後に ? ではなく、パラメータにデフォルト値を指定する形 (string title = null) や OptionalAttribute を使いますが、呼び出し側で省略できる点は同じです。TypeScript同様、通常は必須引数の後に置きます。
  • デフォルトパラメータ (param: type = value):
    • TypeScript: パラメータにデフォルト値を指定できます。呼び出し時に引数が省略されると、このデフォルト値が使われます。例: function power(base: number, exponent: number = 2)
    • C#: C# 4.0以降のデフォルト引数 (int exponent = 2) と完全に同じ概念です。
  • Restパラメータ (...param: type[]):
    • TypeScript: 関数の最後のパラメータとして、... を使うことで可変長の引数を受け取ることができます。受け取った引数は配列として扱われます。例: function sumAll(...numbers: number[]): number
    • C#: C#の params キーワード (params int[] numbers) と同じ目的を果たします。可変長の引数を配列として受け取る機能ですが、構文が異なります。

課題内容:

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

  2. 様々な関数の定義: functions.ts に以下のような関数を定義してみてください。

    // src/functions.ts
    
    // --- 1. 関数型エイリアス ---
    type MathOperation = (x: number, y: number) => number;
    
    // 上記の型エイリアスに適合する関数
    const add: MathOperation = (a, b) => {
      return a + b;
    };
    
    const subtract: MathOperation = (x, y) => x - y; // アロー関数の省略形
    
    console.log(`add(5, 3) = ${add(5, 3)}`);
    console.log(`subtract(5, 3) = ${subtract(5, 3)}`);
    
    // --- 2. オプショナルパラメータ ---
    function greet(name: string, title?: string): string {
      if (title) {
        return `Hello, ${title} ${name}!`;
      } else {
        return `Hello, ${name}!`;
      }
    }
    
    console.log(greet("Hideki")); // title は省略
    console.log(greet("Sato", "Mr."));
    
    // --- 3. デフォルトパラメータ ---
    function power(base: number, exponent: number = 2): number {
      return Math.pow(base, exponent); // base の exponent 乗を計算
    }
    
    console.log(`power(10) = ${power(10)}`); // exponent はデフォルト値の 2 を使用
    console.log(`power(2, 8) = ${power(2, 8)}`); // exponent に 8 を指定
    
    // --- 4. Restパラメータ ---
    function sumAll(...numbers: number[]): number {
      // numbers は number 型の配列になる
      let total = 0;
      for (const num of numbers) {
        total += num;
      }
      // または reduce を使う: return numbers.reduce((sum, current) => sum + current, 0);
      return total;
    }
    
    console.log(`sumAll(1, 2, 3) = ${sumAll(1, 2, 3)}`);
    console.log(`sumAll(10, 20, 30, 40, 50) = ${sumAll(10, 20, 30, 40, 50)}`);
    console.log(`sumAll() = ${sumAll()}`); // 引数なしでもOK (空の配列になる)
    
    // --- 5. this の型付け (おまけ) ---
    // 通常の関数とアロー関数での this の挙動の違いはJavaScriptの重要概念
    // TypeScriptでは関数の第一引数に this を書くことで this の型を注釈できる (コンパイル時に消える)
    interface MyData {
      value: number;
      increment: () => void;
    }
    
    const myObj: MyData = {
      value: 10,
      increment: function(this: MyData) { // 通常関数では this の型を指定可能
         console.log(`Incrementing value from ${this.value}`);
         this.value++;
      }
    };
    
    // アロー関数は定義された場所の this を束縛する (ここではグローバル or undefined)
    // const myObjArrow: MyData = {
    //   value: 20,
    //   increment: () => {
    //     // console.log(this.value); // strictモードやモジュール内では this が期待通りでない可能性
    //   }
    // };
    
    myObj.increment();
    console.log(`Value after increment: ${myObj.value}`);
    
  3. コンパイルと実行:

    • npx tsc でコンパイルし、node dist/functions.js で実行して結果を確認してください。
  4. コミットとPush:

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

関数の様々な記法や型付けを理解することは、TypeScriptを使いこなす上で非常に重要です。試してみてください!