🎉
TypeScriptで関数型プログラミングを行ってみた [fp-ts]
こんにちは。FEチームのMapleです。私たちのチームは、現在のシステムアーキテクチャを見直し、Reactを用いた新しいアーキテクチャへの移行を検討しています。今回は先日TypeScriptで行う関数型プログラミングについて解説していきます。
はじめに
関数型プログラミングは、不変性(Immutability)と純粋関数(Pure Functions)を重視し、副作用を最小限に抑えることで、予測可能でテストしやすいコードを書いていきます。
- バグの減少:副作用が少ないため、予期せぬ動作を防げる。
- コードの再利用性:純粋関数は独立性が高く、再利用が容易。
- テスト容易性:関数が同じ入力で常に同じ出力を返すため、ユニットテストが簡単。
TypeScriptでの関数型プログラミングの基本
不変性の確保
TypeScriptでは、constやreadonlyを使って不変性を確保できます。
const x = 10;
// x = 5; // エラー
interface User {
readonly id: number;
readonly name: string;
}
const user: User = { id: 1, name: 'Alice' };
// user.id = 2; // エラー
純粋関数の作成
純粋関数は、副作用がありません。
const add = (a: number, b: number): number => a + b;
高階関数とラムダ式
関数を引数や戻り値として扱う高階関数を利用できます。
const numbers = [1, 2, 3, 4, 5];
const squaredNumbers = numbers.map((n) => n * n);
実践:データ処理に関数型アプローチを適用
問題
ユーザーのリストから特定の条件に合うユーザーを抽出し、その名前のリストを取得したい。
関数型での解決策
- フィルタリング:条件に合うユーザーを抽出する純粋関数を作成。
- マッピング:ユーザーオブジェクトから名前を取り出す純粋関数を作成。
- 合成:上記の関数を組み合わせて目的の結果を得る。
interface User {
id: number;
name: string;
isActive: boolean;
}
const users: User[] = [
{ id: 1, name: 'Alice', isActive: true },
{ id: 2, name: 'Bob', isActive: false },
{ id: 3, name: 'Carol', isActive: true },
];
const getActiveUsers = (users: User[]): User[] =>
users.filter((user) => user.isActive);
const getUserNames = (users: User[]): string[] =>
users.map((user) => user.name);
const activeUserNames = getUserNames(getActiveUsers(users));
console.log(activeUserNames); // ["Alice", "Carol"]
ライブラリの活用
TypeScriptでより高度な関数型プログラミングを行うために、fp-tsというライブラリを利用しました。
import { Option, some, none } from 'fp-ts/Option';
const findUserById = (id: number): Option<User> => {
const user = users.find((user) => user.id === id);
return user ? some(user) : none;
};
findUserById(1).fold(
() => console.log('User not found'),
(user) => console.log(`Found user: ${user.name}`)
);
副作用の管理
副作用を持つ操作を明示的に扱うために、IO型を使用しました。
import { IO } from 'fp-ts/IO';
const log = (message: string): IO<void> => () => console.log(message);
const program: IO<void> = log('Hello, Functional Programming!');
program(); // "Hello, Functional Programming!" と表示
まとめ
TypeScriptで関数型プログラミングを実践することで、コードの品質と保守性が大幅に向上しました。特に、純粋関数や高階関数、不変性の概念を取り入れることで、バグの発生を抑えつつ、読みやすいコードを書くことができました。
関数型プログラミングに興味のある方は、ぜひTypeScriptで触ってみてください!!
株式会社SODAの開発組織がお届けするZenn Publicationです。 是非Entrance Bookもご覧ください! → recruit.soda-inc.jp/engineer
Discussion