TypeScriptで関数合成(compose)とパイプ処理の書き方を徹底解説!初心者でもわかる入門ガイド
生徒
「先生、TypeScriptでいろいろな関数を組み合わせて処理をしたいんですけど、どうやって書けばいいんですか?」
先生
「いい質問ですね。TypeScriptでは、関数合成(compose)やパイプ処理(pipe)という書き方を使うと、複数の関数を順番につなげて処理できます。」
生徒
「関数をつなげるってどういうことですか?なんだか難しそうです…」
先生
「そんなことはありません。料理のレシピをイメージするとわかりやすいですよ。食材を洗って、切って、焼いて…と順番に作業を組み合わせるのと同じなんです。」
生徒
「なるほど!じゃあプログラムでも、関数を順番に並べることで処理の流れを作れるんですね!」
先生
「その通りです!では、具体的にTypeScriptでの書き方を学んでいきましょう。」
1. 関数合成(compose)とは?
関数合成(compose)とは、複数の関数を「右から左」に向かって順番に実行する方法です。例えば、fとgという2つの関数がある場合、compose(f, g)(x)と書くと「まずg(x)を実行して、その結果をfに渡す」という流れになります。
つまり、最後に書いた関数から順番に実行されるイメージです。
const toUpper = (str: string): string => str.toUpperCase();
const addExclamation = (str: string): string => str + "!";
// compose関数を定義(右から左に処理)
const compose = (...fns: Function[]) => (value: any) =>
fns.reduceRight((acc, fn) => fn(acc), value);
const shout = compose(addExclamation, toUpper);
console.log(shout("hello"));
HELLO!
この例では「hello」という文字列を、まずtoUpperで大文字にし、そのあとaddExclamationで感嘆符を追加しています。
2. パイプ処理(pipe)とは?
パイプ処理(pipe)は、関数合成と似ていますが「左から右」に処理を流していく書き方です。水道のパイプの中を水が流れるように、データが関数を通過して次々に変化していきます。
料理でいうと「野菜を洗う → 切る → 炒める」という順番をそのまま書けるので、直感的で読みやすいのが特徴です。
const toUpper = (str: string): string => str.toUpperCase();
const addExclamation = (str: string): string => str + "!";
// pipe関数を定義(左から右に処理)
const pipe = (...fns: Function[]) => (value: any) =>
fns.reduce((acc, fn) => fn(acc), value);
const shout = pipe(toUpper, addExclamation);
console.log(shout("hello"));
HELLO!
こちらはpipeを使って、toUpper → addExclamationの順番で実行しています。流れがコードの見た目通りなので、初心者でも理解しやすいです。
3. composeとpipeの違い
ここまでで、関数合成(compose)とパイプ処理(pipe)の両方を学びました。違いを整理すると次のようになります。
compose→ 右から左へ実行pipe→ 左から右へ実行
どちらを使っても結果は同じですが、コードの読みやすさで選ぶのが一般的です。特に初心者は「処理の流れが見た目通りになる」pipeを使うと理解しやすいでしょう。
4. 実用例:数値の加工
関数合成やパイプ処理は、文字列だけでなく数値の加工にも便利です。例えば「数値を2倍する → 3を足す → 2乗する」という処理を順番につなげてみましょう。
const double = (n: number): number => n * 2;
const addThree = (n: number): number => n + 3;
const square = (n: number): number => n * n;
const pipe = (...fns: Function[]) => (value: any) =>
fns.reduce((acc, fn) => fn(acc), value);
const calculate = pipe(double, addThree, square);
console.log(calculate(5));
169
この場合の流れは「5を2倍して10 → 3を足して13 → 2乗して169」となります。コードを見ただけで計算の流れがイメージできますね。
5. 初心者が覚えるポイント
最後に、初心者の方が関数合成とパイプ処理を学ぶときのポイントを整理します。
- 関数合成(compose)は右から左に処理が流れる
- パイプ処理(pipe)は左から右に処理が流れる
- どちらも「関数を順番につなげる」という考え方が基本
- 実際のプログラムでは、処理の流れが見やすい
pipeがよく使われる
この2つを理解すると、TypeScriptでの関数型プログラミングの考え方に一歩近づけます。最初は小さな関数をつなげて試し、慣れてきたら複雑な処理にも応用してみましょう。
まとめ
これまでTypeScriptにおける関数合成やパイプ処理の基本から応用までを丁寧に見てきました。あらためてふり返ってみると、これらの考え方は複雑な処理をより読みやすく整理し、ひとつひとつの関数を丁寧に組み合わせることで、より自然な流れのコードを書けるようになる点が大きな魅力だと感じられます。たとえば文字列の加工や数値の計算処理のような日常的なケースでも、関数をつなげて表現するだけで、見通しのよい処理の流れが生まれ、コード全体の意図がわかりやすくなります。また、関数型プログラミングの基本的な考え方に触れることで、プログラムを部品化し、再利用性や保守性を高める書き方を自然に身につけることができます。特にTypeScriptでは型がしっかりしているため、関数同士のつながり方が明確になり、安心してパイプラインを構築できるのも大きな利点です。ここでは、もう一度振り返りとして、関数合成やパイプ処理を活用したサンプルコードを整理しながら、実際にどう使えるのかを確認してみましょう。
サンプルプログラムのもう一例
ここでは、文字列の加工を少し複雑にした例を通して、関数をつなげるメリットをさらに深く理解できるようにしています。たとえば文章を整形し、特定のキーワードを強調し、最後に記号をつけるといった処理をまとめると次のようになります。
const trimText = (str: string): string => str.trim();
const highlightKeyword = (str: string): string => str.replace("関数", "【関数】");
const addPeriod = (str: string): string => str + "。";
const pipe = (...fns: Function[]) => (value: any) =>
fns.reduce((acc, fn) => fn(acc), value);
const formatMessage = pipe(trimText, highlightKeyword, addPeriod);
console.log(formatMessage(" TypeScriptで関数を扱う学習をした "));
このように、細かい処理を小さな関数として切り出しておき、必要な順序でつなぐことで、自然で読みやすい処理の流れをそのままコードとして表現できます。学んだ内容を応用して、自分のプロジェクトでも関数をつなげた書き方を試してみると、コード全体の整理がぐっと楽になるはずです。とくに複数の加工や変換を行う場合、パイプ処理はその流れを視覚的に理解しやすくしてくれるため、初心者の方でも無理なく実践できます。また、composeの書き方も左から右とは対照的に右から左の流れで処理が進むため、既存の関数の組み立て方によってはcomposeのほうが自然に書けるケースもあります。どちらの書き方も柔軟に活用しながら、自分の目的に合った方法を選べるようになると、TypeScriptでのプログラミングが一段と楽しく感じられるでしょう。こうした積み重ねによって、関数型の考え方が身につき、大規模なプロジェクトでも「見通しのよいコード」を意識しながら構築できるようになります。
生徒
「先生、今日の学習で関数をつなげるっていう考え方がすごくよくわかりました。処理の流れが見えるってこんなに気持ちが楽なんですね。」
先生
「そうですね。関数合成やパイプ処理は、複雑に見える処理も『順番に変換していくだけ』という考え方に置き換えられるので、とても実践的なんですよ。」
生徒
「たしかに、ひとつひとつの関数の役割が明確だから、どこを直せばいいかもすぐわかる気がします。」
先生
「その通りです。小さな関数に分けることで、再利用しやすい部品として扱えるようになりますし、プロジェクトが大きくなるほど効果が大きくなります。」
生徒
「これからは、ただ長い処理を書くんじゃなくて、関数を組み合わせながら書いてみます!」
先生
「えらいですね。今日の学びを活かして、処理の流れが読みやすいコードを意識して書いてみてくださいね。」