先に要点
- Effect-TS は 「成功 / 失敗 / 必要な依存」 を型で同時に表す Effect<Success, Error, Requirements> という中核型を持つ TypeScript の 関数型エコシステム。
- 提供範囲は広い: 型付きエラーハンドリング」 「Schema(Zod 競合)」 「Context / DI(依存注入)」 「Retry / Schedule」 「並行 / Fiber」 「Stream」 `Layer によるアプリ構築 など。「1つのエコシステムで堅牢な TS バックエンド」 を組める。
- 思想は Scala の ZIO をベース。「例外を投げる代わりに型でエラーを表す」 「依存は型レベルで表す」 という関数型バックエンドの設計を TS に移植した形。
- 本命の使い所は 堅牢性が重要な TS バックエンド / 複雑な非同期パイプライン / AI ワークフロー。学習コストは大きいが、「チーム全体で型と信頼性を引き上げたい」 案件で大きな価値を出す。
Effect-TS ってよく聞くけど、結局何をするライブラリ? Promise / async-await でいいんじゃないの? 「関数型ってまた難しい話?」 ── 2023 年あたりから TypeScript の関数型コミュニティで急速に存在感を増した Effect-TS は、「TS バックエンドの新しい標準」 を目指す野心的なプロジェクトです。
ざっくり言うと、Effect-TS は 成功・失敗・依存をすべて型で表現する Effect 型を中核に、TS で堅牢なバックエンドを書くためのエコシステム です。 「Promise だと失敗の型が伝わらない」 「関数の依存を引数で渡し続けるのが辛い」 「リトライ / タイムアウト / 並行性を毎回手で書きたくない」 ── こうした TS バックエンド開発の悩みを、体系的に解決する ことを目指しています。
この記事では、2026 年 5 月時点の Effect-TS v3 系をベースに、仕組み・なぜ生まれたか・基本コード・採用判断軸 を整理します。 仕様は活発に変化しているので、最終確認は 公式 を見るのが安全です。
なぜ Effect-TS が生まれたか
「普通の Promise / async-await で何が困るのか」 が分かると、Effect の動機が見えます。
①エラーの型が消える
「Promise<User>」 は 「成功した場合 User を返す」 を示すが、失敗時に何が起きるかは型に表れない。「どんなエラーが投げられるか」 を呼び出し側が知る術がない。
② try / catch だらけ
「 catch でエラーを潰す or 投げ直す」 が散らばる。「どこでエラーが処理されているか」 が見えにくくなる。
④ リトライ / タイムアウトの手書き
「 失敗したら3回までリトライ、間隔は指数バックオフ」 のような典型処理を、案件ごとに書き直す。「本質的に同じコードが10箇所に散らばる」 状態。
Effect は これらすべてを 「Effect 型」 のエコシステムで体系的に扱う ことを目指したライブラリです。
Effect 型の中核
Effect の世界で最も大事な型が Effect<Success, Error, Requirements> です。
import { Effect } from 'effect';
// User を取ってくる Effect(成功時 User、失敗時 UserNotFound、依存 Database)
const getUser = (id: string): Effect.Effect<User, UserNotFound, Database> =>
Effect.gen(function* () {
const db = yield* Database;
const user = yield* db.find(id);
return user;
});
3 つの型パラメータ
「Success」 = 成功時の値、「Error」 = 失敗時のエラー、「Requirements」 = 実行に必要な依存。「 何が起きうるか」 が型で完全に表される。
遅延評価
` Effect は値ではなく 「これからやることの記述」」。「Effect.runPromise(effect)」 で初めて実行される。「Promise はすぐ動く / Effect は明示するまで動かない」 という違い。
「Effect.gen」
「yield*」 を使った Generator 構文で、「async/await のように Effect を書ける」。「pipe」 メソッドチェインより読みやすい。
合成
「Effect.flatMap」 「Effect.map」 「Effect.zip」 で、Effect どうしを安全に合成できる。「成功時の処理」 「失敗時の処理」 が分離されたまま記述できる。
「実行を遅延し、型で失敗と依存を表現する」 のが、Effect の体験を一言で表す部分です。
何が嬉しいか — 具体例
「Promise」 と 「Effect」 で同じ処理を書き比べると、違いが見えます。
Promise 版
async function getUser(id: string): Promise<User> {
const db = getDatabase(); // 依存はグローバル / 引数のどれかでうやむや
try {
return await db.find(id);
} catch (err) {
// どんなエラーが投げられるかは型に出ない
throw new UserNotFound(id);
}
}
// リトライしたい場合は手書き
async function getUserWithRetry(id: string): Promise<User> {
for (let i = 0; i < 3; i++) {
try { return await getUser(id); }
catch (e) { if (i === 2) throw e; }
}
throw new Error('unreachable');
}
Effect 版
const getUser = (id: string) =>
Effect.gen(function* () {
const db = yield* Database; // 依存は型レベルで明示
return yield* db.find(id); // 失敗時の型も追える
});
// リトライは標準機能
const getUserWithRetry = (id: string) =>
getUser(id).pipe(Effect.retry({ times: 3 }));
依存が型に出る
「 Database を必要とすること」 が呼び出し側に型として伝わる。「関数を呼んでみないと依存が分からない」 が消える。
エラーが型に出る
「UserNotFound」 を返しうることが明示される。「どこかで例外が投げられている」 ではなく 「この処理は UserNotFound で失敗する可能性がある」 と読める。
標準のリトライ / スケジュール
「Effect.retry」 「Effect.timeout」 「Effect.race」 「Schedule.exponential」 などが標準提供。「毎回手書きしていた処理」 が宣言的に書ける。
合成可能
「 Effect は値として渡せる」 ので、関数で受け取り、加工して返すことができる。`高階の処理(「withLogging」 「withTimeout」)」 を再利用しやすい。
「型と合成可能性で堅牢な TS バックエンドを書く」 のが Effect の中心的な価値です。
エコシステムの広がり
Effect-TS は Effect 型 + 周辺ライブラリ群 でひとつのエコシステムを形成しています。
| 機能 | 中身 | 競合 / 関連 |
|---|---|---|
| Effect 型 / Fiber | 中心 API、並行・キャンセル制御も統合 | Promise + RxJS |
| Schema | 型と検証を一体化したスキーマ | Zod / Valibot |
| Context / Layer | 依存注入(DI)とアプリ構築 | InversifyJS / 手書き DI |
| Stream | 非同期ストリーム | RxJS / async iterator |
| Schedule | リトライ / 周期実行 | p-retry / 手書きループ |
| STM | ソフトウェアトランザクショナルメモリ | (独自領域) |
| HTTP | HTTP クライアント / サーバ | node-fetch / Hono |
「1つのライブラリで TS バックエンドの基本ピースを全部カバーする」 のが Effect のスケールです。
いつ Effect-TS を選ぶか
「Effect を入れる価値が出る案件」 を整理します。
向いている
① 中〜大規模 TS バックエンド、② 失敗の種類が多く 「どのエラーが起きうるか」 を型で追いたい、③ 複雑な非同期パイプライン(リトライ・並行・タイムアウトが頻出)、④ AI ワークフロー / 外部 API 連携が多い、⑤ 関数型を学習する文化があるチーム。
部分採用も可能
「 全部を Effect で書く」 のではなく、「重要な非同期パイプラインだけ Effect」 という部分採用ができる。tRPC の Procedure 内で Effect を使う、のような構成も。
Zod / Valibot との関係
「 Schema(Effect の検証ライブラリ)」 は Zod と直接競合する。「Effect エコシステムに統一したい」 なら Schema、「独立した検証だけ欲しい」 なら Zod、という棲み分け。
「堅牢な TS バックエンドにコミットできるチーム」 で大きく光るタイプの道具です。
ハマりやすいポイント
便利な反面、現場で踏みやすい注意点も整理します。
①学習コスト
「 Promise の感覚で Effect を書こうとすると混乱する」。Effect は値、実行するには runPromise が必要などのルールに慣れる時間が要る。「数週間〜1ヶ月」 を見ておくと安全。
② 型エラーの読みづらさ
「 高度な型推論」 を使う関係で、型エラーが長く読みにくいことがある。「型シグネチャを明示的に書く」 ことで分かりやすくなる場面が多い。
③ チームの導入合意
「 1人が Effect で書いて、他は Promise」 だと混在して辛い。「チーム全体で採用するか / しないか」 を最初に決める必要がある。
④ パフォーマンス
「 軽量な処理に Effect は重め」。「単純な Promise 呼び出し1個」 を Effect 化するメリットは薄い。「複雑なパイプライン」 ほど Effect が活きる構造。
「良いプログラムを書ける可能性を上げる代わりに、書く側の学習コストを払う」 のが Effect の特徴です。
AI 時代の Effect-TS
AI 連携の文脈で Effect-TS の役割を整理します。
AI ワークフローの型安全
「 LLM 呼び出し → 検証 → 再試行 → タイムアウト処理 → 結果統合」 のような複雑なパイプラインで、Effect の 「エラー / リトライ / 並行」 機能がそのまま使える。AI 系コードの落とし穴を構造的に減らす。
Schema での構造化出力
「 AI に Effect Schema に従った JSON を返させる」 ことで、「AI 出力の検証 + 型推論」 を1つの定義で完結。Zod と同じ思想で、Effect エコシステムに統一できる。
Stream で AI レスポンス
「 ストリーミング応答を Effect Stream で扱う」 ことで、「遅延・キャンセル・タイムアウト」 を統一的に書ける。
「AI 時代の信頼性の高い TS バックエンド」 を作りたいときに、Effect-TS の価値は高まっています。
Effect-TS に関するよくある質問
Q. Effect-TS と Zod、どちらを選ぶべきですか?
A. 検証だけなら Zod、エコシステム全体を Effect で統一するなら Effect Schema。Zod は単体で完結する手軽さ、Effect Schema は 「Effect 型と統合される強み」 がそれぞれの長所です。
Q. Effect-TS は本番運用に耐えますか?
A. 耐えます。Effect は Scala の ZIO の TS 版という長年の設計を継承しており、Vercel・Shopify・Microsoft などの一部チームでも採用事例があります。「採用人口は React ほどではない」 ので、コミュニティが大きい React 系ライブラリほどの情報量は期待できない、と認識しておくのが安全です。
Q. Promise から Effect への移行は大変ですか?
A. 概念の学習が中心です。書き換え自体はそこまで大変ではないですが、「Effect の世界観」 を理解しないと正しく書けません。「小さなコードから順に書き換える」 段階移行が現実的です。
Q. fp-ts との関係は?
A. Effect-TS は fp-ts の後継的な存在として位置づけられています。同じ作者陣の一部が関わっていて、「fp-ts より統合的でモダンな API」 を提供しています。「新規プロジェクトは Effect」 が2026 年現在の標準的な選び方です。
Q. Node.js / Bun / Deno で動きますか?
A. はい、すべてのランタイムで動きます。Web 標準 API ベースのコードが多く、Bun や Deno、Cloudflare Workers などのエッジランタイムでも問題なく使えます。
Q. 学習にどのくらいかかりますか?
A. 基本概念で 1〜2 週間、実プロジェクトで使いこなすまで 1〜2 ヶ月が現実的な感触です。「Promise / async-await に慣れている人ほど、最初の戸惑い」 が大きい傾向。「公式チュートリアル + Effect.gen」 から始めて、徐々に Layer / Schema / Stream に広げると進めやすいです。
Q. Effect-TS を学ぶ最短ルートは?
A. ① 公式の 「Getting Started」 を1セット、② 「Effect.gen + yield*」 で簡単な処理、③ 「Effect.retry / Effect.timeout」 で典型処理、④ 「Context / Layer」 で DI、⑤ 「Schema」 で検証、の5ステップが王道です。「まず Effect.gen を書いて、yield* に慣れる」 のが最初のハードルです。