JavaScript開発者にとって、関数はロジックの中心的な構成要素です。JavaScriptでは引数の数や型が柔軟(あるいはルーズ)ですが、TypeScriptではここを厳密に管理することで、実行時エラーの大半を防ぐことができます。
この章では、TypeScriptにおける関数の型定義の基本から、モダンなJavaScript開発で必須となるアロー関数、そして高度なオーバーロードまでを学習します。
TypeScriptの関数定義において最も基本的なルールは、「引数」と「戻り値」に型を付けることです。
: 型 を記述します。) の後ろに : 型 を記述します。戻り値の型は型推論(Chapter 2参照)によって省略可能ですが、関数の意図を明確にするために明示的に書くことが推奨されます。戻り値がない場合は void を使用します。
// 基本的な関数宣言
function add(a: number, b: number): number {
return a + b;
}
// 戻り値がない関数
function logMessage(message: string): void {
console.log(`LOG: ${message}`);
}
const result = add(10, 5);
logMessage(`Result is ${result}`);
// エラー例(コメントアウトを外すとエラーになります)
// add(10, "5"); // Error: Argument of type 'string' is not assignable to parameter of type 'number'.npx tsc basic_math.ts && node basic_math.jsLOG: Result is 15
JavaScriptでは引数を省略すると undefined になりますが、TypeScriptでは定義された引数は必須とみなされます。引数を省略可能にするには、特別な構文が必要です。
引数名の後ろに ? を付けることで、その引数を省略可能(オプショナル)にできます。省略された場合の値は undefined です。
注意: オプショナル引数は、必ず必須引数の後ろに配置する必要があります。
ES6(JavaScript)と同様に、引数にデフォルト値を指定できます。デフォルト値がある場合、TypeScriptはその引数を「型推論」し、かつ「省略可能」として扱います。
// titleは省略可能
function greet(name: string, title?: string): string {
if (title) {
return `Hello, ${title} ${name}!`;
}
return `Hello, ${name}!`;
}
// powerのデフォルト値は2
// 戻り値の型はnumberと推論されるため省略可能
function exponent(base: number, power: number = 2) {
return base ** power;
}
console.log(greet("Tanaka"));
console.log(greet("Sato", "Dr."));
console.log(`2^2 = ${exponent(2)}`);
console.log(`2^3 = ${exponent(2, 3)}`);npx tsc optional_default.ts && node optional_default.jsHello, Tanaka! Hello, Dr. Sato! 2^2 = 4 2^3 = 8
アロー関数を変数に代入する場合、引数と戻り値の記述場所は通常の関数と同様です。
const multiply = (x: number, y: number): number => {
return x * y;
};
// 1行で書く場合(暗黙のreturn)
const subtract = (x: number, y: number): number => x - y;
console.log(multiply(4, 5));
console.log(subtract(10, 3));npx tsc arrow_func.ts && node arrow_func.js20 7
JavaScriptにおいて this の挙動は複雑ですが、TypeScriptでは this が何を指すかを明示的に型定義できます。
これを行うには、関数の最初の引数として this という名前の「偽の引数」を定義します。これはコンパイル後のJavaScriptには出力されません。
interface User {
name: string;
count: number;
}
function counter(this: User) {
this.count += 1;
console.log(`${this.name}: ${this.count}`);
}
const userA: User = { name: "Alice", count: 0 };
// callメソッドを使ってthisコンテキストを指定して実行
counter.call(userA);
counter.call(userA);
// アロー関数はthisを持たないため、この構文は使いませんnpx tsc this_context.ts && node this_context.jsAlice: 1 Alice: 2
JavaScriptでは「引数の型や数によって挙動が変わる関数」をよく書きます。TypeScriptでこれを表現するにはオーバーロードを使用します。
オーバーロードは以下の2つの部分で構成されます:
// 1. オーバーロードシグネチャ(呼び出し可能なパターン)
function double(value: number): number;
function double(value: string): string;
// 2. 実装シグネチャ(すべてのパターンを網羅できる型定義にする)
function double(value: number | string): number | string {
if (typeof value === 'number') {
return value * 2;
} else {
return value.repeat(2);
}
}
const numResult = double(10); // 型は number として推論される
const strResult = double("Hi"); // 型は string として推論される
console.log(numResult);
console.log(strResult);
// double(true); // エラー: booleanを受け入れるオーバーロードはありませんnpx tsc overload.ts && node overload.js20 HiHi
ポイント: 実装シグネチャ(
number | stringの部分)は直接呼び出せません。必ず上で定義したシグネチャ(numberまたはstring)に一致する必要があります。
引数の数が可変である場合(可変長引数)、JavaScriptと同様に ...args 構文を使用します。
TypeScriptでは、この args は必ず配列の型である必要があります。
// 数値を好きなだけ受け取り、合計を返す
function sumAll(...numbers: number[]): number {
return numbers.reduce((total, num) => total + num, 0);
}
// 文字列を結合する
function joinStrings(separator: string, ...words: string[]): string {
return words.join(separator);
}
console.log(sumAll(1, 2, 3, 4, 5));
console.log(joinStrings("-", "TypeScript", "is", "fun"));npx tsc rest_params.ts && node rest_params.js15 TypeScript-is-fun
コールバック関数を引数に取る場合など、関数の型定義が長くなりがちです。
第3章で学んだ type(型エイリアス)を使って、関数のシグネチャそのものに名前を付けることができます。
構文: type 型名 = (引数: 型) => 戻り値の型;
// 関数の型定義を作成
type MathOperation = (x: number, y: number) => number;
// 作成した型を適用
const addition: MathOperation = (a, b) => a + b;
const multiplication: MathOperation = (a, b) => a * b;
// 高階関数での利用例(関数を受け取る関数)
function compute(x: number, y: number, op: MathOperation): number {
return op(x, y);
}
console.log(compute(10, 2, addition));
console.log(compute(10, 2, multiplication));npx tsc func_alias.ts && node func_alias.js12 20
? でオプショナル引数、= でデフォルト引数を定義できます。this の型付けもサポートされており、コンテキストミスを防げます。以下の要件を満たす findUser 関数をアロー関数として作成してください。
id (number) と name (string) を受け取る。name はオプショナル引数とする。SearchFunc として先に定義し、それを適用すること。npx tsc practice4_1.ts && node practice4_1.js以下の要件を満たす convert 関数を function キーワードで作成してください。
number の場合、それを string に変換して返す(例: 100 -> "100")。string の場合、それを number に変換して返す(例: "100" -> 100)。npx tsc practice4_2.ts && node practice4_2.js