TypeScriptでは、関数に型を付けることで、引数や戻り値に対して静的型チェックが行えるようになり、コードの安全性と可読性が向上します。この記事では、関数の型付けに関する基本的な方法から、応用的なパターンまでを解説します。
1. 関数の基本的な型付け
TypeScriptでは、関数の引数と戻り値に対して型を指定することができます。以下は、基本的な関数の型付けの例です。
function greet(name: string): string {
return `Hello, ${name}!`;
}
console.log(greet("TypeScript")); // "Hello, TypeScript!"
引数の型付け
上記の例では、name
という引数にstring
型を指定しています。関数を呼び出す際に、string
型以外の値を渡すとコンパイルエラーになります。
greet(123); // エラー: 'number'型の引数は'string'型のパラメーターに割り当てられません。
戻り値の型付け
関数の戻り値にも型を指定できます。greet
関数はstring
型を返すことが明示されており、もし異なる型を返す場合はエラーが発生します。
function greet(name: string): number {
return `Hello, ${name}!`; // エラー: 'string'型の値は'number'型に割り当てられません。
}
2. 関数の型推論
TypeScriptは関数の戻り値を自動的に推論するため、戻り値の型を省略することもできます。ただし、明示的に型を指定することで、コードがより明確になり、他の開発者が読みやすくなります。
function sum(a: number, b: number) {
return a + b; // 戻り値は自動的にnumber型と推論される
}
3. オプショナル引数とデフォルト引数
関数の引数が必須でない場合、オプショナル引数やデフォルト引数を使うことができます。
オプショナル引数
オプショナル引数は、引数の後ろに?
を付けて定義します。この場合、引数を渡さなくてもエラーにはなりません。
function greet(name: string, age?: number): string {
if (age) {
return `Hello, ${name}! You are ${age} years old.`;
}
return `Hello, ${name}!`;
}
console.log(greet("Alice")); // "Hello, Alice!"
console.log(greet("Alice", 30)); // "Hello, Alice! You are 30 years old."
デフォルト引数
デフォルト引数は、引数に値が渡されなかった場合に使用するデフォルトの値を指定できます。
function greet(name: string = "Guest"): string {
return `Hello, ${name}!`;
}
console.log(greet()); // "Hello, Guest!"
console.log(greet("Alice")); // "Hello, Alice!"
4. 関数型(Function Type)
関数の型自体を定義することもできます。関数型は、引数と戻り値の型を指定して、関数の型を表現します。
let add: (a: number, b: number) => number;
add = (x, y) => x + y;
console.log(add(2, 3)); // 5
この例では、add
変数に対して「a
とb
がnumber
型で、戻り値もnumber
型の関数」という型を指定しています。これにより、他の型の関数を代入しようとするとエラーになります。
add = (x: string, y: string) => x + y; // エラー: 型が一致しません
5. コールバック関数の型
コールバック関数を使用する際も、引数として渡す関数に型を指定することができます。これにより、期待されるコールバックの型を保証し、型の不一致によるエラーを防ぎます。
function map(array: number[], callback: (value: number) => number): number[] {
return array.map(callback);
}
const result = map([1, 2, 3], (value) => value * 2);
console.log(result); // [2, 4, 6]
この例では、callback
関数がnumber
型の値を引数に取り、number
型を返す関数であることが型定義で保証されています。
6. 可変長引数(Rest Parameters)
TypeScriptでは、関数に可変長引数を指定することができます。可変長引数を使うことで、関数が任意の数の引数を受け取れるようになります。
function sum(...numbers: number[]): number {
return numbers.reduce((total, num) => total + num, 0);
}
console.log(sum(1, 2, 3)); // 6
console.log(sum(1, 2, 3, 4, 5)); // 15
...numbers
は可変長引数を表しており、関数に渡された引数はnumber[]
の配列として扱われます。
7. オーバーロード(関数の多重定義)
TypeScriptでは、同じ関数名で異なる引数型や戻り値型を持つ関数を定義することができます。これを関数のオーバーロードと呼びます。
function display(value: string): void;
function display(value: number): void;
function display(value: any): void {
if (typeof value === "string") {
console.log(`String: ${value}`);
} else if (typeof value === "number") {
console.log(`Number: ${value}`);
}
}
display("Hello"); // String: Hello
display(123); // Number: 123
この例では、display
関数がstring
型またはnumber
型の引数を受け取れることを示しています。実装部分では、typeof
を使って型に応じた処理を行っています。
8. ジェネリクスを使った関数型
ジェネリクスを使うことで、関数に汎用的な型を付けることができます。これにより、異なる型の引数に対しても同じ関数ロジックを再利用できます。
function identity<T>(value: T): T {
return value;
}
console.log(identity<string>("Hello")); // "Hello"
console.log(identity<number>(123)); // 123
この例では、T
という型パラメータを使用し、引数と戻り値が同じ型であることを保証しています。呼び出し時に型を明示することで、様々な型に対応した関数を作成できます。
まとめ
TypeScriptでは、関数に対して引数や戻り値の型を明確に指定することで、予期しないバグを防ぎ、より安全で保守性の高いコードを記述できます。基本的な引数や戻り値の型指定だけでなく、コールバック関数の型やオーバーロード、ジェネリクスを活用した柔軟な関数型の定義まで、TypeScriptの強力な型システムを使って関数の型付けを行いましょう。