TypeScriptでカリー化関数を作る方法と利点を徹底解説!初心者でもわかる関数テクニック
生徒
「先生、TypeScriptで『カリー化関数』っていう言葉を聞いたんですけど、どういう意味ですか?」
先生
「良いところに気づきましたね。カリー化関数とは、複数の引数を一度に受け取る関数を、引数をひとつずつ受け取る関数に分解して書けるようにした関数のことです。」
生徒
「ちょっと難しそうですが、便利なんですか?」
先生
「はい、とても便利です。例えば同じ処理を繰り返すときに、コードをシンプルにできる利点があります。実際の例を見ながら説明しましょう。」
1. カリー化とは?
まず「カリー化(カリーか)」という言葉の意味から理解していきましょう。カリー化とは、複数の引数を持つ関数を、引数をひとつだけ受け取る関数の連鎖に変換する方法です。名前は数学者「ハスケル・カリー」に由来しています。
例えば、普通の関数では次のように書きます。
function add(a: number, b: number): number {
return a + b;
}
console.log(add(2, 3)); // 5
この関数をカリー化すると、「引数をひとつずつ受け取る」関数に書き直せます。
function addCurried(a: number): (b: number) => number {
return function(b: number): number {
return a + b;
};
}
console.log(addCurried(2)(3)); // 5
ポイントは、addCurried(2) が「bを受け取る関数」を返しているところです。つまり、関数を途中まで実行して「次に受け取る引数を待つ関数」を作れるのです。
2. TypeScriptでカリー化関数を使う利点
TypeScriptでカリー化関数を使うと、次のような3つのメリットがあります。
- コードの再利用性が高まる:途中で関数を保存して使い回せる。
- 処理の分割がわかりやすい:一度に全部を処理するより、分けて考えやすい。
- 型安全で安心:TypeScriptが引数の型をチェックしてくれるので、間違いが減る。
例えば「2を足す関数」をあらかじめ作っておけば、毎回「2」を入力する必要がなくなります。
const add = (a: number) => (b: number) => a + b;
const add2 = add(2); // 2を足す関数を作成
console.log(add2(5)); // 7
console.log(add2(10)); // 12
7
12
このように、カリー化を使うと「一部の引数を固定した新しい関数」を簡単に作れるのです。
3. 日常生活の例えで理解するカリー化
プログラミング未経験の方には「注文の流れ」に例えると分かりやすいです。
普通の関数は「一度に全部注文するレストラン」です。
- 「ラーメンと餃子をください」 → すぐに調理開始。
一方、カリー化関数は「順番に注文するレストラン」です。
- 「ラーメンください」 → 店員がメモ。
- 「餃子もください」 → 注文が完成して調理開始。
このように、ひとつずつ注文を積み重ねていけるのがカリー化のイメージです。
4. カリー化関数の型定義
TypeScriptは型を明示的に書けるので、カリー化関数でも安心して使えます。
type Add = (a: number) => (b: number) => number;
const add: Add = (a) => (b) => a + b;
console.log(add(3)(4)); // 7
typeで型を定義しておけば、引数や戻り値が正しく使われているかを自動でチェックしてくれます。
5. カリー化を応用した使い方
カリー化関数は「関数の組み合わせ」で特に力を発揮します。例えば文字列を操作する処理を作ってみましょう。
const append = (suffix: string) => (str: string) => str + suffix;
const addExclamation = append("!");
console.log(addExclamation("Hello")); // Hello!
const addQuestion = append("?");
console.log(addQuestion("Hello")); // Hello?
Hello!
Hello?
このように「カリー化関数で部品を作る」と、いろいろな組み合わせで処理を作りやすくなります。
まとめ
ここまで、TypeScriptにおけるカリー化関数の仕組みや書き方、その実践的な使い道について、実際のコードとともに詳しく学んできました。カリー化という考え方は、最初は少し独特に感じられるかもしれませんが、ひとつずつ処理を積み上げていくという発想に慣れると、関数の再利用性や柔軟性がぐっと高まり、日常的なプログラミングに自然と活かせる便利な技法だと実感できるようになります。 特にTypeScriptのように型を活用した開発を行う場合、カリー化は「途中まで準備した状態の関数を再利用できる」という利点が際立ち、複雑な処理を分解して扱いやすくしたり、必要な引数だけを先に固定して新しい関数を作り出したりと、関数設計の幅が広がります。関数同士を組み合わせる時にも相性がよく、文字列操作や数値処理、さらには状態を徐々に積み上げていくフォーム入力など、さまざまな用途で活用することができます。 もちろん、カリー化はただ難しいテクニックというわけではありません。むしろ、「ひとつの処理をより細かく分けて扱いやすくする」という、やさしい設計の発想でもあります。コードの見通しをよくし、チーム開発でも意図を共有しやすい書き方にできるため、TypeScript初心者にとっても学んで損のない考え方です。
■ カリー化の理解を深めるサンプルプログラム
ここでは、学んだ内容の振り返りとして、より実践的なカリー化関数の例をひとつ紹介します。複数のデータに対して同じ加工を加える場面では、カリー化によって処理の「ひな型」を作り出し、必要に応じて使い回すことができます。
/**
* 文字列を加工するためのカリー化関数
* prefix と suffix を段階的に設定できるようにする
*/
const decorate = (prefix: string) => (suffix: string) => (text: string) => {
return prefix + text + suffix;
};
// 「★」で挟む関数を生成
const starDecorate = decorate("★")("★");
console.log(starDecorate("TypeScript")); // ★TypeScript★
/**
* 応用例:商品名を飾り付ける関数
*/
const wrap = decorate("[")("]");
console.log(wrap("カリー化関数")); // [カリー化関数]
このように、「文字を飾り付ける」という抽象的な処理をカリー化しておくと、目的に応じて異なる関数を作りやすくなり、コードの読みやすさも向上します。関数を段階的に組み立てられるという特性は、柔軟で見通しのよいロジックを作るうえで非常に強力です。実務でも役立つ理解なので、ぜひ色々とカスタマイズしながら試してみてください。
生徒
「先生、今日のカリー化の話、最初は難しいと思ったけど、コードを見たら思ったよりシンプルで驚きました。」
先生
「そうですね。カリー化は一見専門的な言葉ですが、やってみると『ひとつの引数を順番に受け取る関数』というだけなので、とても扱いやすい考え方なんです。」
生徒
「特に、途中まで引数を固定して新しい関数が作れるのが便利だと感じました。add(2) みたいな関数も自然に書けるんですね。」
先生
「ええ、あれは実務でもよく使われるテクニックですよ。共通処理をうまく切り分けて、後から組み合わせるようなイメージで活用できます。」
生徒
「なるほど…。カリー化って、ただのテクニックじゃなくて、設計を工夫するための道具なんですね。」
先生
「そのとおり。使いこなせるようになると、関数を組み合わせる発想が自然と身について、より綺麗で再利用性の高いコードが書けるようになりますよ。」