第7章:関数とその型定義

【TypeScript入門シリーズ】第7章:関数とその型定義

TypeScriptでは、関数を定義する際に型を注釈することで、関数の引数や戻り値の型を明確に指定できます。これにより、関数の使い方に誤りがある場合、コンパイル時にエラーを検出できるため、型安全なコードを実現することができます。

この章では、TypeScriptにおける関数の基本的な定義方法から、型注釈、関数型、可変長引数、デフォルト引数など、さまざまな関数の使い方を解説していきます。


6.1 関数の基本

関数は、複数のコードをまとめて再利用可能にするための最も基本的なプログラム構造の一つです。TypeScriptでは、関数の引数や戻り値に型を指定することで、型安全性を強化します。

6.1.1 関数の定義

JavaScriptと同様に、TypeScriptでは関数宣言関数式の両方を使って関数を定義できますが、TypeScriptでは型注釈が追加されます。

function add(x: number, y: number): number {
return x + y;
}

この関数では、xyという引数がnumber型であり、戻り値もnumber型であることを明示しています。関数のシグネチャが明確になるため、意図しない引数の誤りや型ミスマッチを防ぐことができます。

6.1.2 関数式の定義

関数式を使って関数を定義することもできます。この方法では、変数に関数を割り当てます。

const multiply = function(a: number, b: number): number {
return a * b;
};

ここでも、引数と戻り値に型注釈を付けています。関数式は、関数を変数に代入できるため、関数を柔軟に扱うことが可能です。


6.2 関数に対する型注釈

TypeScriptの型注釈は、関数の引数や戻り値に対しても使うことができます。これにより、関数をより安全かつ明確に定義することができます。

6.2.1 引数の型注釈

関数の引数に型を指定することで、その引数にどのような型のデータが渡されるべきかを明示できます。

function greet(name: string): string {
return `Hello, ${name}!`;
}

この例では、greet関数の引数であるnamestring型であることを指定しています。このように型注釈を追加することで、引数に数値や他の型が渡された場合には、コンパイルエラーが発生します。

6.2.2 戻り値の型注釈

関数の戻り値の型も、関数定義の後にコロンを使って明示的に指定できます。これにより、関数がどの型の値を返すべきかを保証できます。

function square(num: number): number {
return num * num;
}

この関数では、引数numnumber型であり、戻り値もnumber型であることが明示されています。TypeScriptは、戻り値が型に合わない場合にエラーを出力します。

6.2.3 型推論と型注釈

TypeScriptは非常に強力な型推論の機能を持っており、引数や戻り値に明示的な型注釈をつけなくても、適切な型を推論してくれます。

function addNumbers(a: number, b: number) {
return a + b; // TypeScriptは戻り値をnumber型と推論
}

この例では、戻り値の型がnumber型であると推論されているため、明示的に型注釈を追加する必要はありません。ただし、複雑な関数や可読性を高めるために、戻り値の型注釈を明示することが推奨される場合もあります。


6.3 デフォルト引数とオプション引数

TypeScriptでは、関数の引数にデフォルト値を設定したり、オプションで引数を受け取るように定義することができます。これにより、柔軟な関数を定義することが可能です。

6.3.1 デフォルト引数

デフォルト引数を使うと、関数呼び出し時に引数が渡されなかった場合に、デフォルトの値が適用されます。引数にデフォルト値を設定するには、引数の型定義の後に等号=でデフォルト値を指定します。

function greetUser(name: string = "Guest"): string {
return `Hello, ${name}!`;
}

console.log(greetUser()); // "Hello, Guest!"
console.log(greetUser("Alice")); // "Hello, Alice!"

この例では、name引数にデフォルト値"Guest"が設定されています。引数が渡されなかった場合でも、エラーが発生せず、デフォルトの動作が適用されます。

6.3.2 オプション引数

オプション引数は、関数呼び出し時に必ずしも渡される必要がない引数です。オプション引数を定義するには、引数名の後ろに?をつけます。

function printMessage(message: string, author?: string): string {
if (author) {
return `${message} - by ${author}`;
} else {
return message;
}
}

console.log(printMessage("Welcome!")); // "Welcome!"
console.log(printMessage("Welcome!", "Admin")); // "Welcome! - by Admin"

この例では、author引数がオプションになっており、引数が渡されなかった場合でも関数は正常に動作します。


6.4 可変長引数(rest parameters)

TypeScriptでは、可変長引数(rest parameters)を使って、任意の数の引数を受け取る関数を定義することができます。可変長引数は、関数の引数リストに...をつけることで定義します。

function sumAll(...numbers: number[]): number {
return numbers.reduce((total, num) => total + num, 0);
}

console.log(sumAll(1, 2, 3)); // 6
console.log(sumAll(10, 20, 30, 40)); // 100

この例では、numbers引数が可変長引数として定義されており、任意の数の数値を配列として受け取ります。可変長引数を使うことで、柔軟な関数を作成できます。


6.5 関数型

関数型を使うと、関数自体に型を付けることができます。これにより、関数そのものを引数や戻り値として扱う場合や、関数を変数に代入する場合に型を定義できます。

6.5.1 関数型の定義

関数型は、引数の型と戻り値の型を定義したシグネチャによって表されます。以下の例では、関数型を使って関数を定義しています。

let add: (x: number, y: number) => number;

add = function(a: number, b: number): number {
return a + b;
};

console.log(add(5, 3)); // 8

この例では、add変数に対して、(x: number, y: number) => numberという関数型が指定されています。この型は、「number型の引数を2つ受け取り、number型の値を返す関数」であることを意味しています。

6.5.2 コールバック関数の型定義

TypeScriptでは、関数を引数として渡すことも一般的です。この場合、コールバック関数の型を定義することで、関数の引数や戻り値の型を明確にし、型安全性を高めることができます。

function processNumbers(numbers: number[], callback: (num: number) => void): void {
numbers.forEach(callback);
}

processNumbers([1, 2, 3], (num) => {
console.log(num * 2);
});
// 2, 4, 6

この例では、callbackとして渡される関数の型が(num: number) => voidとして定義されています。このように、コールバック関数のシグネチャを明確に指定することで、型の安全性を保証できます。


6.6 アロー関数

アロー関数は、より簡潔に関数を記述するための構文です。アロー関数は関数式の一種であり、functionキーワードの代わりに=>を使います。アロー関数は特に短い関数を記述する際に便利です。

let multiply = (x: number, y: number): number => {
return x * y;
};

console.log(multiply(5, 3)); // 15

アロー関数は、従来の関数に比べて短く書けるだけでなく、thisキーワードの挙動が異なる点でも特徴的です。アロー関数では、外部のthisが自動的にバインドされるため、クラスメソッドなどでのコールバック関数内でのthisの扱いが簡単になります。


6.7 型のオーバーロード

TypeScriptでは、同じ名前の関数に対して複数の異なるシグネチャを定義する関数のオーバーロードをサポートしています。これにより、同じ関数が異なる引数の型や数に対して異なる処理を行うことができます。

function combine(a: string, b: string): string;
function combine(a: number, b: number): number;
function combine(a: any, b: any): any {
if (typeof a === "string" && typeof b === "string") {
return a + b;
} else if (typeof a === "number" && typeof b === "number") {
return a + b;
}
}

console.log(combine("Hello, ", "World!")); // "Hello, World!"
console.log(combine(10, 20)); // 30

この例では、combine関数に対して2つの異なるシグネチャを定義し、文字列や数値に対して適切な処理を行っています。オーバーロードを使うことで、関数を柔軟に扱うことが可能になります。


まとめ

この章では、TypeScriptにおける関数とその型定義について詳しく学びました。関数に型注釈をつけることで、型安全な関数を定義し、引数や戻り値のミスマッチによるバグを防ぐことができます。また、可変長引数やデフォルト引数、関数型、コールバック関数、アロー関数など、関数の多彩な使い方を学びました。