プログラミング ソフトウェア 公開日 2026.05.15 更新日 2026.05.20

Effect-TS とは何か?TypeScript の関数型エコシステムとエラー・依存・並行を型で扱う設計

Effect-TS は 「成功 / 失敗 / 必要な依存」 を型で表現する 「Effect 型」 を中心に据えた TypeScript の関数型エコシステムです。エラーハンドリング・依存注入・スキーマ検証・リトライ / スケジュール・並行・Stream まで1つの基盤でカバーします。Scala ZIO の思想を TS に移植した形で、AI 時代の堅牢な TS バックエンドで注目されています。

先に要点

  • 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 投げ直す」 が散らばる。「どこでエラーが処理されているか」 が見えにくくなる。

③ 依存注入の手書き

「 関数が DB / API / Logger を必要とするとき、引数で受け取る」 のがチームで揃わず、「ファクトリ / シングルトン / グローバル変数」 が混在する。

④ リトライ / タイムアウトの手書き

「 失敗したら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 連携が多い、⑤ 関数型を学習する文化があるチーム。

慎重に

① 小規模スクリプト / MVP、② チームに関数型の経験が薄い、③ 学習コストをかけられない案件、④ シンプルな CRUD 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 を使った業務システム」 は外部 API の信頼性が低めなので、「リトライ / 並行 / フォールバック」 のデフォルトが整っていることが価値になる。

「AI 時代の信頼性の高い TS バックエンド」 を作りたいときに、Effect-TS の価値は高まっています。

Effect-TS に関するよくある質問

Q. Effect-TS と Zod、どちらを選ぶべきですか?

A. 検証だけなら Zod、エコシステム全体を Effect で統一するなら Effect SchemaZod は単体で完結する手軽さ、Effect Schema は 「Effect 型と統合される強み」 がそれぞれの長所です。

Q. Effect-TS は本番運用に耐えますか?

A. 耐えます。Effect は Scala の ZIO の TS 版という長年の設計を継承しており、VercelShopify・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 ベースのコードが多く、BunDenoCloudflare 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* に慣れる」 のが最初のハードルです。

参考リンク

あとで見返すならここで保存

読み終わったあとに残しておきたい記事は、お気に入りからまとめて辿れます。