関数型プログラミング(FP)は「副作用を抑え、関数を組み合わせる」プログラミングスタイルです。完全に関数型でなくとも、その考え方を取り入れるとコードがシンプルで読みやすくなります。本記事では、JavaScript/TypeScriptで学ぶ関数型の基本を解説します。
関数型の基本的な考え方
- 純粋関数:同じ入力なら同じ出力、副作用なし
- イミュータブル:値を変更せず新しい値を作る
- 第一級関数:関数を引数・戻り値として扱う
- 合成:小さな関数を組み合わせて大きな処理を作る
純粋関数とは
// 純粋
const add = (a, b) => a + b;
// 非純粋(副作用あり)
let counter = 0;
const inc = () => { counter++; return counter; };
イミュータブルなデータ操作
// NG:元の配列を変更
const arr = [1, 2, 3];
arr.push(4);
// OK:新しい配列を作る
const arr2 = [...arr, 4];
// オブジェクトも同じ
const user2 = { ...user, name: 'B' };
高階関数:map / filter / reduce
const nums = [1, 2, 3, 4, 5];
const doubled = nums.map(n => n * 2);
const evens = nums.filter(n => n % 2 === 0);
const sum = nums.reduce((a, b) => a + b, 0);
関数合成
const pipe = (...fns) => (x) => fns.reduce((v, f) => f(v), x);
const toUpper = s => s.toUpperCase();
const exclaim = s => s + '!';
const shout = pipe(toUpper, exclaim);
shout('hello'); // 'HELLO!'
カリー化(部分適用)
const add = (a) => (b) => a + b;
const add10 = add(10);
add10(5); // 15
Option / Resultパターン
例外ではなく「値で失敗を表す」。null/undefinedより明示的で安全です。
type Result<T, E> = { ok: true; value: T } | { ok: false; error: E };
function parseInt2(s: string): Result<number, string> {
const n = Number(s);
return Number.isFinite(n)
? { ok: true, value: n }
: { ok: false, error: `invalid: ${s}` };
}
実務での活用
- Reactのstate更新はイミュータブル前提(Immerも便利)
- 配列処理はforよりmap/filter/reduce
- 副作用(API呼び出し・DOM操作)は端に集める
- テストは純粋関数中心に書くと楽
まとめ
関数型プログラミングは「全部関数型にする」ではなく、純粋関数・イミュータブル・高階関数といった発想を取り入れるだけで効果絶大です。日常のJS/TSコードに混ぜていけば、テストしやすく副作用に強いコードになっていきます。