TypeScriptで関数の型を定義する方法について、実践的な例を交えながら詳しく解説します。
基本的な関数の型定義
TypeScriptでは、関数の引数と戻り値の型を明示的に指定することができます。
// 基本的な関数の型定義
function add(a: number, b: number): number {
return a + b;
}
// アロー関数での型定義
const multiply = (x: number, y: number): number => {
return x * y;
};関数型の変数定義
関数型を変数に代入する場合は、以下のように定義します。
// 関数型の変数定義
type MathOperation = (x: number, y: number) => number;
const divide: MathOperation = (a, b) => {
return a / b;
};オプショナルパラメータとデフォルト値
引数を省略可能にしたり、デフォルト値を設定したりできます。
// オプショナルパラメータ(?を使用)
function greet(name: string, greeting?: string): string {
return greeting ? `${greeting}, ${name}!` : `Hello, ${name}!`;
}
// デフォルト値の設定
function calculateTotal(price: number, taxRate: number = 0.1): number {
return price * (1 + taxRate);
}関数のオーバーロード
同じ関数名で異なる引数のパターンを定義できます。
// オーバーロードシグネチャ
function processInput(input: number): number;
function processInput(input: string): string;
function processInput(input: number | string): number | string {
if (typeof input === "number") {
return input * 2;
} else {
return input.toUpperCase();
}
}ジェネリック関数
型パラメータを使用して、柔軟な型定義が可能です。
// ジェネリック関数の定義
function firstElement<T>(arr: T[]): T | undefined {
return arr[0];
}
// 使用例
const numbers = firstElement([1, 2, 3]); // number型
const strings = firstElement(["a", "b", "c"]); // string型Rest Parameters
可変長引数を受け取る関数の型定義もできます。
function sum(...numbers: number[]): number {
return numbers.reduce((total, n) => total + n, 0);
}コールバック関数の型定義
コールバック関数を引数に取る関数の型定義方法です。
function fetchData(callback: (data: string) => void): void {
// データ取得の処理
callback("取得したデータ");
}async/await関数の型定義
非同期関数の型定義は、Promise型を使用します。
async function fetchUser(id: number): Promise<User> {
const response = await fetch(`/api/users/${id}`);
return response.json();
}型ガード関数
型の絞り込みを行う関数の定義方法です。
function isString(value: unknown): value is string {
return typeof value === "string";
}メソッドの型定義
クラス内のメソッドの型定義方法です。
class Calculator {
add(a: number, b: number): number {
return a + b;
}
static multiply(x: number, y: number): number {
return x * y;
}
}以上の型定義パターンを適切に組み合わせることで、型安全な関数を実装できます。エラーの早期発見やコードの保守性向上に役立ちます。
実際の開発では、これらの型定義を状況に応じて使い分けることが重要です。特に、ジェネリックやオーバーロードは、柔軟で再利用可能なコードを書く際に非常に有用です。