PR

TypeScript:関数宣言/関数式の基本を1分でわかりやすく

TypeScript
Q
そもそも「関数」とは?
A
  • プログラムで繰り返し使われる処理のかたまりのことです。
  • 例えば「足し算を行う処理」「メッセージを表示する処理」など、それぞれの処理をまとめておくことで、何度でも呼び出して使えるようになります。
    TypeScript 関数
    図1:関数のイメージ

    関数を使うメリット

    1. 再利用性: 同じコードを何度も書かずに済む。
    2. 可読性: コードを機能ごとに分けることで読みやすくなる。
    3. 保守性: 一か所を修正すれば、すべての呼び出し箇所に反映される。

    このページでは、TypeScriptでの関数定義・関数の呼び出し方法を1からわかりやすく解説します。

    スポンサーリンク

    TypeScript:関数の定義方法

    TypeScriptは基本的にはJavascriptの上位互換言語なので、TypeScriptで関数を定義する方法もJavascriptと同様2つあります:関数宣言関数式です。

    ポイント 関数宣言

    function 関数名(引数: 型, 引数2: 型, ...): 戻り値の型 {
      // 処理
      return 値;
    }
    

    ポイント 関数式

    const 関数名 = function(引数: 引数型, ...): 戻り値の型 {
        処理;
    };
    

    基本的にはJavascriptにおける関数定義を理解していれば、TypeScriptではそこに型の指定が追加されるだけで基本的な動作は全く同じ。「そもそも関数って何?」という方は、以下のページで1から詳しく解説しておりますので、まずは以下をご覧ください。

    関数に型をつけるメリット

    TypeScript では、JavaScript に型の仕組みが加わりました。
    引数や戻り値に型を指定することで、次のようなメリットがあります。

    • バグの予防: 型が違う値を間違えて渡してしまうミスを防げる。
    • 補完機能の向上: エディタでメソッドや引数のサジェストが適切に表示される。
    • 可読性の向上: 「この関数にはどういう型の引数を渡すのか、どんな型の値が返ってくるのか」が明確になる。

    TypeScript:関数宣言

    function 関数名(引数: 型, 引数2: 型, ...): 戻り値の型 {
      // 処理
      return 値;
    }
    
    • 引数名と型の間はコロン(:)で区切る
    • 戻り値の型を () の後ろにコロンで指定する
    • 何も返さない場合は void 型を指定する

    サンプルコード 引数に型を指定する例

    function greet(name: string) {
      console.log(`Hello, ${name}!`);
    }
    
    greet("Alice");  // OK: string 型
    greet(42);       // エラー: number は string に代入できない
    

    greet("Alice") は問題なく動作します。greet(42) は引数が数値のため、TypeScript がエラーを出してくれます。これによって、引数に想定外の型が渡されるミスを未然に防げます。

    サンプルコード 戻り値の型を指定する例

    function add(a: number, b: number): number {
      return a + b;
    }
    
    const result = add(2, 3);
    console.log(result); // 5
    

    関数 addnumber 型を返す、と明示しています。実際に文字列を返そうとすると、コンパイラが「戻り値が number じゃないよ」と教えてくれます。

    サンプルコード 戻り値がない場合(void 型)

    function logMessage(message: string): void {
      console.log(message);
    }
    

    何も返さない(return がない)場合や、戻り値を使わない場合は void を指定します。

    引数が任意(オプション)の場合

    JavaScriptと同様、関数の引数は任意にすることができます。任意の引数は、引数名の後に?をつけて定義します。オプショナルな引数は、呼び出し時に省略可能です。

    function greetOptional(name?: string): void {
      console.log(`Hello, ${name || "Guest"}!`);
    }
    
    greetOptional("Bob"); // "Hello, Bob!"
    greetOptional();      // "Hello, Guest!"
    

    name?: string と書くことで「name は必須ではなくてもいい」という指定ができます。実際に呼び出すときに引数を渡さない場合、nameundefined になります。

    そのため、 || "Guest" の部分でフォールバック処理を行っています。(フォールバック処理については後述

    デフォルトパラメータ

    引数を省略したときにデフォルトで使われる値を指定できます。

    function greetDefault(name: string = "Guest"): void {
      console.log(`Hello, ${name}!`);
    }
    
    greetDefault("Charlie"); // "Hello, Charlie!"
    greetDefault();          // "Hello, Guest!"
    

    デフォルト引数を使うと、オプション引数のように ? をつけなくても同等のことが実現できます。

    TypeScript:関数式

    関数式は関数を変数に割り当てる方法で、匿名関数(名前のない関数)を使用して定義されます。これは、JavaScriptの関数式の概念を型の安全性とともに拡張したものです。関数式は、即時実行が必要な場合や、コールバック関数として他の関数に渡す必要がある場合に特に便利です。

    const myFunction = function(parameter1: type, parameter2: type, ...): returnType {
        // 関数の本体
    };
    • function キーワードを使って無名関数を定義します。
    • 関数を変数または定数に代入します。
    • 型指定は引数や戻り値に対して行います。

    サンプルコード 基本的な関数式

    const add = function(a: number, b: number): number {
        return a + b;
    };
    
    console.log(add(3, 5)); // 実行結果: 8
    

    ポイント

    • function の後に関数名をつけない(無名関数)。
    • 引数 abnumber 型を指定。
    • 戻り値の型を : number として指定。

    サンプルコード オプション引数とデフォルト引数を組み合わせる

    const greet = function(name?: string, greeting: string = "Hello"): void {
        console.log(`${greeting}, ${name || "Guest"}!`);
    };
    
    greet("Alice");        // 実行結果: Hello, Alice!
    greet(undefined, "Hi"); // 実行結果: Hi, Guest!
    

    ポイント

    • オプション引数 name?: string により、引数がなくてもエラーになりません。
    • greeting 引数にデフォルト値 "Hello" を設定。

    関数式/アロー関数の特徴と利点

    基本的な関数宣言と比較して、関数式を用いる利点は以下の通り。ざっくり言えば、手軽にかつ簡潔に記述できる点が関数式のメリット。(ここらへんもJavaScriptと同様です!)

    1. 名前のない関数(匿名関数)
      • 関数式は名前を持たないため、一時的な処理や即時実行関数に適しています。
    2. 型の安全性
      • TypeScriptの型システムを利用することで、引数と戻り値に対する型の安全性が保証されます。
    3. 高階関数
      • 関数を他の関数に引数として渡したり、関数から別の関数を戻り値として返すパターンに適しています。

    TypeScript:アロー関数

    アロー関数(Arrow Function)は、JavaScriptおよびTypeScriptで利用できる関数の簡潔な書き方です。関数式をより短く記述できるほか、this の挙動が従来の関数とは異なるという特徴があります。

    const 関数名 = (引数: 型, ...) => {
        処理;
    };
    
    • 引数リストの後にアロー => を記述し、処理内容を {} 内に記述します。
    • 戻り値を明示する場合、型を「(): 戻り値の型」で指定します。

    アロー関数の例

    サンプルコード 引数を持たない場合

    以下は引数を持たないアロー関数の例です。

    const greet = (): void => {
        console.log("Hello, World!");
    };
    greet(); // 実行結果: Hello, World!
            

    引数がない場合でも、() は省略できません。

    サンプルコード 引数が1つの場合

    引数が1つのアロー関数では、() を省略することができます。

    const greet = (name: string): void => {
        console.log(`Hello, ${name}!`);
    };
    greet("Alice"); // 実行結果: Hello, Alice!
            

    さらに、以下のように簡潔に記述することも可能です。

    const greet = name => console.log(`Hello, ${name}!`);
            

    サンプルコード 戻り値がある場合

    アロー関数で戻り値を持たせる場合の例です。

    const add = (a: number, b: number): number => {
        return a + b;
    };
    console.log(add(2, 3)); // 実行結果: 5
            

    処理が1行の場合は、{} と return を省略できます。

    const add = (a: number, b: number): number => a + b;
            

    TypeScript:関数の実行

    TypeScriptで関数を実行する方法も基本的にはJavaScriptの関数の実行方法と同様です。関数を実行するには、関数名に続けて括弧()を書き、括弧の中に必要な引数をコンマで区切って渡します。引数が不要な場合でも、括弧は必須です。

    関数宣言の場合

    関数宣言を使用して関数を定義した場合、その関数は定義されたスコープ内のどこからでも呼び出すことができます。

    // 関数の定義
    function greet(name: string): string {
        return `Hello, ${name}!`;
    }
    
    // 関数の実行
    const message = greet("Alice");
    console.log(message);  // 出力: Hello, Alice!

    関数式の場合

    関数式で関数を定義した場合、その関数は関数式が割り当てられた変数を通じて呼び出します。

    // 関数式の定義(アロー関数を使用)
    const add = (x: number, y: number): number => {
        return x + y;
    };
    
    // 関数の実行
    const sum = add(5, 7);
    console.log(sum);  // 出力: 12

    即時実行関数式 (IIFE)

    即時実行関数式(Immediately Invoked Function Expression)は、定義された直後に自動的に実行される関数です。TypeScriptでのIIFEもJavaScriptと同様に書けますが、型安全性の利点があります。

    // 即時実行関数式の例
    ((name: string) => {
        console.log(`Hello, ${name}!`);
    })("Alice");

    この例では、アロー関数を使用したIIFEが定義され、"Alice"が引数として渡されています。この関数は、定義された直後に一度だけ実行されます。

    高階関数の実行

    高階関数(他の関数を引数として受け取る関数や、関数を戻り値として返す関数)も同様に実行できます。

    // 高階関数の例
    function repeat(times: number, action: (index: number) => void): void {
        for (let i = 0; i < times; i++) {
            action(i);
        }
    }
    
    // 高階関数の実行
    repeat(3, (index) => {
        console.log(`This is iteration number ${index}`);
    });

    ↑の例では、repeat関数は2つの引数を受け取ります:実行回数と、各反復で実行するアクションを定義する関数です。これらの例からわかるように、TypeScriptでの関数の実行は、関数の種類や定義方法にかかわらず、直感的で柔軟なものであることが分かります。

    TypeScript:関数に関するテクニック

    TypeScriptの関数を使いこなす上では基本的な定義や実行方法の理解に加えて、いくつかの重要な概念や機能を把握しておくと良いでしょう。ここからは、TypeScriptの型システムを活用し、より安全で保守しやすいコードを書くためにおさえておきたい重要ポイントをご説明します。

    ジェネリック型

    ジェネリック型を関数に適用することで、関数をより柔軟に再利用可能にすることができます。ジェネリック型を使用すると、関数が受け取る引数や返す戻り値の型を呼び出し時に指定できるようになります。

    function identity<T>(arg: T): T {
        return arg;
    }
    
    let output = identity<string>("myString");
    let outputNumber = identity<number>(100);

    ↑の例では、identity関数は任意の型Tの値を受け取り、同じ型の値を返します。これにより、同一の関数構造を異なる型で使用することができます。

    オーバーロード

    TypeScriptでは関数のオーバーロードをサポートしており、同じ名前の関数を異なる引数の型や数で複数定義することができます。これにより、関数の引数に応じて異なる処理を実行することが可能になります。

    function makeDate(timestamp: number): Date;
    function makeDate(m: number, d: number, y: number): Date;
    function makeDate(mOrTimestamp: number, d?: number, y?: number): Date {
        if (d !== undefined && y !== undefined) {
            return new Date(y, mOrTimestamp, d);
        } else {
            return new Date(mOrTimestamp);
        }
    }

    この例では、makeDate関数はタイムスタンプを受け取るバージョンと、月、日、年を個別に受け取るバージョンの2つの呼び出し方ができます。

    タプルとデストラクチャリング

    関数の引数や戻り値としてタプルを使用することで、複数の値を効率的に扱うことができます。また、デストラクチャリングを使うことで、これらの値を簡単に取り出すことができます。

    function useState<T>(initialValue: T): [T, (newValue: T) => void] {
        let value = initialValue;
        const setValue = (newValue: T) => {
            value = newValue;
        };
        return [value, setValue];
    }
    
    const [counter, setCounter] = useState(0);

    ↑の例では、useState関数は状態の値と、その状態を更新する関数をタプルとして返します。このようなパターンは、ReactのHooks APIで広く採用されています。

    これらの概念を理解し、適切に活用することで、TypeScriptでの関数の使いこなし度が深まり、より複雑なアプリケーションの開発にも対応できるようになります。

    タイトルとURLをコピーしました