TypeScript の関数型
関数はJavaScriptの中核をなす構成要素であり、TypeScriptでは関数の引数や戻り値に包括的な型システムが追加されており、関数の「入力」と「出力」が明確に定義されるようになっています。
1. 関数型のアノテーション
(1) パラメータおよび戻り値の型
TYPESCRIPT
function add(a: number, b: number): number {
return a + b;
}
let result = add(1, 2); // result Inferred as number
// add("1", "2"); // ❌ Parameter types do not match
// add(1); // ❌ Insufficient number of parameters
(2) 戻り値型の推論
TypeScript は return 文に基づいて戻り値の型を推論できますが、明示的に指定することをお勧めします:
TYPESCRIPT
// Return Type Inference——Can be inferred, but not recommended(It's easy to make mistakes when deriving large functions)
function multiply(a: number, b: number) {
return a * b; // Inference Return number
}
// Explicit Annotation——Recommendations(Purpose of the Document + Compile-time errors)
function divide(a: number, b: number): number {
if (b === 0) throw new Error("The divisor cannot be zero.");
return a / b;
}
(3) void 戻り値の型
関数の戻り値がない場合は、void を使用してください:
TYPESCRIPT
function log(message: string): void {
console.log(message);
// None return Statement,Or return; —— All of them void
}
(4) 値を返さない
関数が決して値を返さず、例外をスローするか、無限ループに入る場合は、never を使用してください:
TYPESCRIPT
function throwError(message: string): never {
throw new Error(message);
}
function infiniteLoop(): never {
while (true) { }
}
| 戻り値の型 | 意味 |
|---|---|
void |
関数は正常に実行されたが、値を返さなかった |
never |
関数が終了しない(例外が発生するか、無限ループに陥る) |
▶ 例:型付きユーティリティ関数
TYPESCRIPT
function clamp(value: number, min: number, max: number): number {
return Math.min(Math.max(value, min), max);
}
function formatCurrency(amount: number, symbol: string = "¥"): string {
return symbol + amount.toFixed(2);
}
console.log(clamp(150, 0, 100)); // 100
console.log(clamp(-5, 0, 100)); // 0
console.log(clamp(50, 0, 100)); // 50
console.log(formatCurrency(99.5)); // ¥99.50
console.log(formatCurrency(42, "$")); // $42.00
出力:
TEXT
100
0
50
¥99.50
$42.00
2. オプションのパラメータとデフォルトのパラメータ
(1) オプションパラメータ ?
TYPESCRIPT
function greet(name: string, title?: string): string {
if (title) {
return `${title} ${name}`;
}
return `Hello,${name}`;
}
console.log(greet("Charlie")); // "Hello,Charlie"
console.log(greet("Charlie", "Engineer")); // "Engineer Charlie"
⚠️ ルール:オプションのパラメータは、必須のパラメータの後に指定する必要があります。
function greet(title?: string, name: string) とするとエラーになります。
(2) デフォルトのパラメータ
TYPESCRIPT
function createUser(name: string, role: string = "viewer", active: boolean = true): string {
return `${name},Characters:${role},${active ? "Active" : "Not activated"}`;
}
console.log(createUser("Charlie")); // Charlie,Characters:viewer,Active
console.log(createUser("Diana", "editor")); // Diana,Characters:editor,Active
console.log(createUser("Eric", "admin", false)); // Eric,Characters:admin,Not activated
(3) オプションのパラメータとデフォルトのパラメータ
| 機能 | オプションパラメータ title?: string |
デフォルトパラメータ role: string = "viewer" |
|---|---|---|
| 呼び出されたとき | 省略可能。値は未定義 | 省略可能。値はデフォルト値 |
| タイプ | string | undefined |
string(未定義の共用体ではない) |
| 推奨事項 | その値は確かに未定義である可能性がある | ほとんどの場合、妥当なデフォルト値を設定しておくほうがよい |
3. その他のパラメータ
... という構文を使用して、残りのパラメータを配列にまとめます:
TYPESCRIPT
function sum(first: number, ...rest: number[]): number {
return rest.reduce((total, n) => total + n, first);
}
console.log(sum(1)); // 1
console.log(sum(1, 2)); // 3
console.log(sum(1, 2, 3, 4)); // 10
(1) 残りのパラメータは配列型でなければならない
TYPESCRIPT
function logAll(prefix: string, ...messages: string[]): void {
messages.forEach(msg => console.log(`${prefix}: ${msg}`));
}
logAll("DEBUG", "Start the service", "Connect to the Database", "Ready");
出力:
TEXT
DEBUG: Start the service
DEBUG: Connect to the Database
DEBUG: Ready
4. 関数型式
関数は値渡しすることも可能です。その場合、型を指定するために関数型式が使用されます:
(1) 型エイリアスは関数型を定義する
TYPESCRIPT
type MathOperation = (a: number, b: number) => number;
let add: MathOperation = (a, b) => a + b;
let subtract: MathOperation = (a, b) => a - b;
let multiply: MathOperation = (a, b) => a * b;
console.log(add(10, 5)); // 15
console.log(subtract(10, 5)); // 5
console.log(multiply(10, 5)); // 50
(2) コールバック関数の型
関数型の最も一般的な用途は、コールバック関数のシグネチャを記述することです:
TYPESCRIPT
function fetchData(url: string, onSuccess: (data: string) => void, onError: (error: Error) => void): void {
// Simulating Asynchronous Operations
if (url.startsWith("https://")) {
onSuccess("Data loaded successfully");
} else {
onError(new Error("Supports only HTTPS"));
}
}
fetchData(
"https://api.example.com",
data => console.log(data), // ✅ (data: string) => void
error => console.log(error.message) // ✅ (error: Error) => void
);
(3) インターフェースを用いた関数型の定義
TYPESCRIPT
interface Comparator {
(a: number, b: number): number;
}
let ascending: Comparator = (a, b) => a - b;
let descending: Comparator = (a, b) => b - a;
let nums = [3, 1, 4, 1, 5];
console.log([...nums].sort(ascending)); // [1, 1, 3, 4, 5]
console.log([...nums].sort(descending)); // [5, 4, 3, 1, 1]
5. 関数のオーバーロード
関数のオーバーロードにより、1つの関数名で引数の型のさまざまな組み合わせに対応できるようになります。TypeScriptのオーバーロードは、「宣言+実装」というパターンに従います:
(1) 基本的な構文
TYPESCRIPT
// Overloaded Signatures——Describe the return type for each parameter combination
function format(value: number): string;
function format(value: string): string;
function format(value: Date): string;
// Implementing Signatures——Must be compatible with all overloaded signatures
function format(value: number | string | Date): string {
if (typeof value === "number") {
return value.toFixed(2);
} else if (typeof value === "string") {
return value.trim();
} else {
return value.toISOString();
}
}
console.log(format(3.14)); // "3.14"
console.log(format(" hello ")); // "hello"
console.log(format(new Date())); // "2024-..."
(2) オーバーロードの順序
TypeScript は、オーバーロードされたメソッドを宣言された順序(上から下へ)で照合するため、より具体的なオーバーロードを先に記述する必要があります:
TYPESCRIPT
// ✅ Correct Order——The specifics come first
function process(value: string): string;
function process(value: any): unknown;
// ❌ Incorrect Order——any Matches all parameters,The overloaded version that comes later will never be called.
// function process(value: any): unknown;
// function process(value: string): string;
▶ 例:型安全なイベント処理を実装するためのオーバーロード
TYPESCRIPT
function on(event: "click", handler: (x: number, y: number) => void): void;
function on(event: "keydown", handler: (key: string) => void): void;
function on(event: string, handler: Function): void {
console.log(`Registration Event:${event}`);
// Implementation details omitted...
}
// Automatically determines the correct parameter types upon invocation
on("click", (x, y) => {
console.log(`Click here:(${x}, ${y})`); // x, y Inferred as number
});
on("keydown", (key) => {
console.log(`Press the button:${key}`); // key Inferred as string
});
6. 矢印関数の種類
(1) 矢印関数の型注釈
TYPESCRIPT
const add = (a: number, b: number): number => a + b;
// When acting as a callback,Parameter types can usually be inferred
const nums = [1, 2, 3];
const doubled = nums.map(n => n * 2); // n Inferred as number
const asStrings = nums.map(n => String(n)); // n Inferred as number
(2) 矢印関数と this
矢印関数は独自の this をバインドせず、外側の this を継承します:
TYPESCRIPT
class Timer {
seconds = 0;
start() {
// Arrow Functions——this Orientation Timer Examples
setInterval(() => {
this.seconds++;
console.log(`${this.seconds}s`);
}, 1000);
}
startBroken() {
// Ordinary Functions——this Points to the global or undefined(Strict Mode)
setInterval(function () {
// this.seconds++; // ❌ Runtime this No Timer
}, 1000);
}
}
❓ よくある質問
Q 関数の戻り値の型は明示的に指定すべきですか?
A 指定することをお勧めします。TypeScriptでは型推論が可能ですが、明示的に指定することには3つの利点があります:(1) ドキュメント化――戻り値の型が一目でわかります;(2) 誤って間違った型の値を返すのを防げます;(3) エラーの特定が容易になります――エラーは呼び出し箇所ではなく、関数のシグネチャで報告されます。短い関数(1行の関数
return)では戻り値の型を省略しても構いませんが、3行を超える関数では明示的に指定することを推奨します。Q 戻り値の型
void と undefined の違いは何ですか?A
void は「関数は戻り値を気にしない」という意味です。つまり、関数に return 文がある場合もあればない場合もあり、呼び出し側は戻り値を使用すべきではありません。undefinedは特定の型であり、関数は明示的にundefinedを返します。実際の開発では、戻り値のない関数はすべてvoidを使用します。Q 関数のオーバーロードとユニオン型パラメータの違いは何ですか?
A ユニオン型
function fn(x: string | number) は、「パラメータがこれらの型のいずれかである」ことを記述することしかできませんが、すべてのパラメータの組み合わせが同じ型を返します。オーバーロードでは、「異なるパラメータの組み合わせによって異なる型を返す」ことが可能ですが、これはユニオン型では実現できません。パラメータの型に柔軟性があり、戻り値の型が統一されている場合は、ユニオン型を使用する方が簡潔です。異なる戻り値の型が必要な場合は、オーバーロードを使用してください。Q デフォルトパラメータとオプションパラメータを併用することはできますか?
A いいえ。
function fn(x?: string = "hi") は構文エラーです。デフォルトパラメータはすでに「オプション」であることが暗黙的に想定されているため、? を追加する必要はありません。x: string = "hi" は x?: string と同等ですが、その値は未定義ではなく「hi」となります。📖 まとめ
- 関数の型注釈:パラメータの型には必ず型注釈を付ける必要があります。戻り値の型については、型注釈を付けることが推奨されます。「void」は戻り値がないことを示し、「never」は関数が決して戻らないことを示します。
- オプションのパラメータには
?を使用してください(値が未定義の場合があります)。デフォルトのパラメータには= defaultValueを使用してください(デフォルト値を設定しておく方が安全です)。 - 残りのパラメータ
...args: type[]余分なパラメータを配列にまとめます - 関数型式
type Fn = (parameter) => returnValueは、コールバックや高階関数を記述するために使用されます - 関数のオーバーロードは「宣言+実装」というパターンに従います。宣言では各引数の組み合わせに対する戻り値の型が指定され、実装はすべてのオーバーロードと互換性がある必要があります。
📝 練習問題
- 基本演習(難易度 ⭐):パラメータと戻り値の両方が型
numberである 3 つの関数、すなわち加算用のadd(a, b)、減算用のsubtract(a, b)、乗算用のmultiply(a, b)を実装してください。関数型式を使用して、型を統一的に宣言してください。 - 上級問題(難易度 ⭐⭐):オブジェクトをURLのクエリ文字列に変換する関数
buildQuery(params: Record<string, string | number | boolean>)を作成してください。例えば、{ page: 1, size: 10, active: true }→"page=1&size=10&active=true"のように変換します。 - 課題(難易度 ⭐⭐⭐):関数のオーバーロードを使用してこれを実装してください
createElement(tag, props):タグが「input」の場合は props はtype: stringでなければなりません;タグが「a」の場合は props はhref: stringでなければなりません;タグが「div」の場合は props はジェネリックオブジェクトとなります。各ケースごとに異なるタイプの説明オブジェクトを返すこと。



