TypeScriptの関数・クロージャまとめ!実践的な使い方と設計パターン
生徒
「TypeScriptで関数やクロージャってよく聞くんですけど、どういうものなんですか?」
先生
「関数はプログラムの中で繰り返し使える処理のまとまりのことです。そしてクロージャは、関数が自分の外側にある変数を覚えておける仕組みのことを指します。」
生徒
「外側の変数を覚えるって、どういうイメージですか?」
先生
「たとえば“冷蔵庫”をイメージするとわかりやすいです。冷蔵庫に入れた食材を覚えておけば、後から取り出して使えるように、クロージャは外の変数を覚えて後で使えるんです。」
1. TypeScriptの関数とは?
まず、関数とはプログラムの処理をひとつにまとめたものです。何度も使いたい処理を関数にまとめておくことで、コードを短く整理できます。日常生活で言えば「料理のレシピ」のようなものです。レシピを見ながら同じ手順で料理を作るように、関数も呼び出せば同じ動きをします。
TypeScriptでは、関数に型を指定できるため、引数や戻り値にどんな値が使えるのかを明確に書けます。
function add(a: number, b: number): number {
return a + b;
}
console.log(add(3, 5));
8
この例では、aとbはnumber型で、結果もnumber型になります。型を指定することで、文字列を間違って渡してしまうなどのエラーを防げます。
2. 関数式とアロー関数
関数の書き方にはいくつか種類があります。ひとつは通常の関数宣言ですが、もうひとつは関数式やアロー関数です。アロー関数は見た目がシンプルで、短い処理を書くときに便利です。
const multiply = (x: number, y: number): number => {
return x * y;
};
console.log(multiply(4, 6));
24
このように、=>を使って関数を定義します。アロー関数は特にJavaScriptやTypeScriptの開発現場でよく使われています。
3. クロージャとは?
クロージャとは、関数が外のスコープ(範囲)にある変数を覚えて使える仕組みです。スコープとは、変数や関数が有効な範囲のことを指します。
例を見てみましょう。
function createCounter() {
let count = 0;
return function () {
count++;
return count;
};
}
const counter = createCounter();
console.log(counter());
console.log(counter());
console.log(counter());
1
2
3
このコードでは、createCounter関数の中でcountという変数を定義しています。通常ならcreateCounterが終わるとcountは消えてしまいますが、返された関数(クロージャ)がcountを覚えているので、呼び出すたびに数字が増えていきます。
4. クロージャの実践的な使い方
クロージャは、データを外部から直接触らせずに管理できるため、安全にプログラムを作りたいときに役立ちます。たとえば、銀行口座の残高のように勝手に書き換えられたくない情報を守るイメージです。
function createBankAccount(initialBalance: number) {
let balance = initialBalance;
return {
deposit: (amount: number) => {
balance += amount;
return balance;
},
withdraw: (amount: number) => {
if (balance >= amount) {
balance -= amount;
} else {
console.log("残高不足です");
}
return balance;
},
getBalance: () => balance
};
}
const account = createBankAccount(1000);
console.log(account.deposit(500));
console.log(account.withdraw(300));
console.log(account.getBalance());
1500
1200
1200
ここでは、残高balanceを直接触れないようにし、depositやwithdrawなどの関数を通じてしか操作できないようにしています。これにより、不正に値を書き換えられるのを防ぐことができます。
5. 設計パターンとしての活用
クロージャは単に便利な機能というだけでなく、設計パターンとしてよく利用されます。特に「情報を隠す(カプセル化)」ための手法として活用できます。オブジェクト指向に近い考え方を、関数とクロージャで実現できるのです。
また、イベント処理やコールバック関数の中で外側の状態を保持したいときにもクロージャは役立ちます。ウェブサイトのボタンをクリックした回数を数えるといった機能もクロージャで実装できます。
まとめ
ここまで、TypeScriptにおける関数の基本構造から、アロー関数の使い方、さらにクロージャによる状態管理の仕組みや応用パターンまで幅広く学んできました。関数はプログラムの処理を整理し、何度も使える形にまとめるための大切な構文であり、TypeScriptでは型を伴って明確に記述できるため、より安全に扱えるという特徴があります。また、クロージャは関数が外側の変数を記憶し続ける仕組みであり、内部に状態を閉じ込めながら安全にデータを扱えるという強力な特徴を持っています。 関数とクロージャの組み合わせは、複雑なロジックを分割し、整理し、意図を読みやすいコードとしてまとめるための重要な技術です。たとえば「クリック回数の管理」「内部の状態を保持したまま戻り値を変化させる関数」「外部から直接アクセスさせたくないデータの保護」など、日常的なプログラミング場面で大いに役立つ考え方です。また、設計パターンとしても活用しやすく、関数型プログラミングの理解にもつながるため、TypeScriptを使ううえで避けて通れない基礎でもあります。 ここからは、今まで学んだ内容を踏まえつつ、理解をさらに深めるための実践的なサンプルコードを紹介し、どのように関数とクロージャを活用できるのかを具体的に振り返っていきます。
■ 関数とクロージャを活用した実践サンプルコード
下記は、ユーザーの操作回数を記録するカウンター機能を関数とクロージャで実装した例です。外側の変数を安全に管理しながら、内部状態を保持したまま連続して使えるようにしています。
function createClickTracker(label: string) {
let count = 0;
return {
0click0: () => {
count++;
console.log(`${label}のクリック回数: ${count}`);
return count;
},
reset: () => {
count = 0;
console.log(`${label}のカウンターをリセットしました。`);
},
getCount: () => count
};
}
const buttonTracker = createClickTracker("ボタンA");
buttonTracker.0click0();
buttonTracker.0click0();
console.log(buttonTracker.getCount());
buttonTracker.reset();
console.log(buttonTracker.getCount());
このコードでは、countという変数が外から直接操作されないようクロージャ内部に保護されています。外部からは0click0・reset・getCountといったメソッドを通してのみ状態を変更できるため、安全性や一貫性を保ちながら動作を管理できます。このように、クロージャは「状態を覚え続ける関数」を柔軟に定義できるため、ユーザーの操作履歴や入力管理、イベント処理などに重宝します。
また、関数を返す関数(高階関数)として利用することで、動作を段階的に設定できる柔軟な仕組みも作れます。以下は、メッセージに装飾を付ける関数を段階的に組み立てる例です。
function createFormatter(prefix: string) {
return function (suffix: string) {
return function (text: string) {
return `${prefix}${text}${suffix}`;
};
};
}
const infoFormatter = createFormatter("[情報]")(":");
console.log(infoFormatter("操作が完了しました"));
ここでは、関数を三段階で生成し、最後に文字列を渡すことで完成形として出力します。関数とクロージャを組み合わせることで、柔軟性が高く再利用性のある処理の組み立てが可能になります。実務でも設定値を保持した関数や、イベントに合わせた動作を記憶する処理など、多彩な場面で活躍する考え方です。
関数とクロージャの理解が深まると、プログラム構造の柔軟性が大きく広がります。外側の情報にアクセスしながら内部だけで状態を保持する仕組みは、複雑なアプリケーション設計の基礎にもなります。ぜひ、今回のサンプルを参考に、さまざまな処理を自分なりに変えて試してみてください。
生徒
「先生、クロージャって難しいイメージがあったけど、実際の動きを見ると意外と親しみやすかったです!」
先生
「そうですね。外の変数を覚えてくれるという点だけ理解できれば、あとは応用範囲が広い便利な仕組みです。」
生徒
「クリック回数の管理みたいに、実際のアプリでも必要になりそうだなと思いました。」
先生
「その通り。ボタンの操作記録、フォーム入力、ゲームのスコア管理など、色んな場面で使われています。」
生徒
「外から勝手に書き換えられないように守る仕組みとしても便利なんですね。」
先生
「はい。データを安全に扱いながら、必要な機能だけ公開するという設計ができます。関数とクロージャは奥が深いので、ぜひ色々な場面で試してみてください。」