Effect-TS/effect — 導出ルール集
出典: repos/Effect-TS/effect/ | 生成日: 2026-02-18 用途: CLAUDE.md にそのまま貼り付けて AI コンテキストとして活用
型安全性
[MUST]エラー型には_tagフィールドをリテラル型で定義し、discriminated union として型安全にパターンマッチできるようにする- 根拠: error-handling-idioms — 全エラー型が
_tagリテラル型でcatchTag/catchTagsによる型安全ディスパッチを実現
- 根拠: error-handling-idioms — 全エラー型が
[MUST]構造的型付けで区別すべき型にはunique symbolを TypeId として付与し、interface のフィールドとして埋め込む- 根拠: type-system-patterns — Option, Either, Effect, Layer 等すべてのデータ型に
TypeId: unique symbolを持たせ型レベルで区別
- 根拠: type-system-patterns — Option, Either, Effect, Layer 等すべてのデータ型に
[MUST]型パラメータの分散(共変/反変/不変)は関数型ファントムフィールド(Covariant<A>,Contravariant<A>,Invariant<A>)でエンコードする- 根拠: type-system-patterns — 全データ型が
outアノテーションとファントムフィールドを併用し、型互換性の正確な制御を実現
- 根拠: type-system-patterns — 全データ型が
[MUST]条件型で union の分配を防ぐ必要がある場面では[T] extends [...]のタプルラッパーを使う- 根拠: type-system-patterns — 全型抽出ユーティリティ(
Effect.Context,Effect.Error等)が一貫してこのパターンを適用
- 根拠: type-system-patterns — 全型抽出ユーティリティ(
[SHOULD]型の識別にはinstanceofではなくSymbol.for()ベースの TypeId +hasProperty型ガードを使う- 根拠: abstraction-patterns — CJS/ESM 混在・ホットリロード・バンドラー重複で
instanceofが壊れるのを回避
- 根拠: abstraction-patterns — CJS/ESM 混在・ホットリロード・バンドラー重複で
[SHOULD]ブランド型は intersection(A & Brand<K>)として実装し、元の型の操作を保持しつつ型レベルの区別を追加する- 根拠: type-system-patterns —
Brand.Branded<A, K> = A & Brand<K>でブランド付きの number が算術演算可能なまま型区別を実現
- 根拠: type-system-patterns —
[SHOULD]型抽出ユーティリティ(Type<S>,Error<S>等)はデータ型のdeclare namespace内に配置し、名前空間を整理する- 根拠: type-system-patterns —
Effect.Context<T>,Schema.Type<S>等で namespace 内に型ユーティリティを集約し API の発見容易性を向上
- 根拠: type-system-patterns —
[SHOULD]型レベルでエラーを報告する場面ではリテラル文字列型を返し、開発者に原因を伝える- 根拠: type-system-patterns —
Brand.EnsureCommonBaseが"ERROR: All brands should have the same base type"を返す設計
- 根拠: type-system-patterns —
[AVOID]型パラメータの分散をout/inアノテーションのみに依存しファントムフィールドでのエンコーディングを省略すること- 根拠: type-system-patterns — コンパイラバージョン間で挙動が変わるリスクがあり、Effect-TS は二重の安全策を取っている
エラーハンドリング
[MUST]エラーを変換・ラップする際は元のエラーをcauseフィールドに保持し、エラーチェーンを途切れさせない- 根拠: error-handling-idioms — 全エラー変換箇所で
new XxxError({ cause, method })として元エラーを保持
- 根拠: error-handling-idioms — 全エラー変換箇所で
[MUST]複数の失敗モードを持つ計算のエラー型は discriminated union(_tag付き)で定義する- 根拠: effect-model —
catchTag/catchTagsは_tagフィールドを前提にExcludeで型を除去する設計
- 根拠: effect-model —
[SHOULD]回復可能なエラー(ドメインエラー)と回復不能なエラー(バグ)を型レベルで分離し、回復不能エラーは明示的に別チャネルに移す- 根拠: error-handling-idioms —
ParseErrorをdieで欠陥に昇格させリトライ対象から除外するパターン
- 根拠: error-handling-idioms —
[SHOULD]エラー型にreasonフィールドをリテラルユニオン型で持たせ、同一エラー種別内の原因を構造的に分類する- 根拠: error-handling-idioms —
RequestErrorの"Transport" | "Encode" | "InvalidUrl"等で_tag+reasonの二層分類を統一
- 根拠: error-handling-idioms —
[SHOULD]モジュール境界でエラー型を変換し、内部実装のエラー型を呼び出し側に漏洩させない- 根拠: error-handling-idioms —
SqlEventJournalが内部SqlErrorをEventJournalErrorにラップして公開 API のエラー型を制御
- 根拠: error-handling-idioms —
[SHOULD]エラークラスにget message()getter を定義し、構造化フィールドから人間向けメッセージを合成する- 根拠: error-handling-idioms — 全パッケージのエラークラスが統一的にこのパターンを実装
[SHOULD]構造化エラーは tagged union のツリーとして表現し、複数のフォーマッタ(人間向け、機械向け)で変換可能にする- 根拠: schema-validation —
ParseIssueが葉ノード/複合ノードの tagged union で TreeFormatter と ArrayFormatter が同一ツリーから異なる出力を生成
- 根拠: schema-validation —
[AVOID]例外をキャッチしてunknown型のまま型チャネルに流す — 必ず具体的なエラー型に変換してから失敗させる- 根拠: error-handling-idioms — コードベースの全箇所で
catchを指定して具体型に変換
- 根拠: error-handling-idioms — コードベースの全箇所で
API 設計
[MUST]dual API を提供する関数では、data-first の実装を 1 つ書きdual(arity, body)で data-last バリアントを自動導出する- 根拠: api-design-practices — 593 箇所の
dual使用すべてがこのパターンに従い実装の一元管理を実現
- 根拠: api-design-practices — 593 箇所の
[MUST]Refinement(型ガード)オーバーロードは、同じシグネチャの Predicate オーバーロードより前に宣言する- 根拠: api-design-practices — TypeScript のオーバーロード解決は宣言順であり、順序を誤ると型絞り込みが効かない
[SHOULD]同名の操作(map,filter等)を複数のデータ型に提供する場合は、名前空間 re-export で衝突を回避しType.operation形式で提供する- 根拠: api-design-practices — 175 個の
export * as X fromによりArray.map,Option.mapが衝突せず共存
- 根拠: api-design-practices — 175 個の
[SHOULD]data-first スタイルの第 1 引数はself、第 2 引数以降のデータ引数はthatと命名する- 根拠: api-design-practices — 全モジュールで統一されパイプライン中のデータフロー把握を容易にしている
[SHOULD]data-last オーバーロードのコールバック型引数にはNoInfer<A>を適用し、コールバックからのジェネリック型逆推論を防止する- 根拠: api-design-practices —
Array.tsで 31 箇所のNoInfer使用によりパイプライン中の型推論が安定
- 根拠: api-design-practices —
[AVOID]ライブラリ API で data-last のみの関数を提供すること — パイプライン外での直接呼び出しが不自然になる- 根拠: api-design-practices — Effect は全操作関数を
dualで両対応させておりdata-last 専用関数は存在しない
- 根拠: api-design-practices — Effect は全操作関数を
モジュール設計とパッケージ構造
[MUST]公開 API(src/*.ts)と内部実装(src/internal/*.ts)を物理的に分離し、公開モジュールにはロジックを書かず re-export に徹する- 根拠: architecture — 177 公開モジュールすべてが
= internal.*形式で export し API 安定性とリファクタリング自由度を両立
- 根拠: architecture — 177 公開モジュールすべてが
[MUST]package.jsonのexportsフィールドで"./internal/*": nullを設定し、内部モジュールへの外部アクセスをブロックする- 根拠: project-structure — 全 30+ パッケージが宣言し Node.js のモジュール解決レベルで内部実装のインポートを拒否
[MUST]モノレポのパッケージ間依存は DAG を維持し、循環依存検出を CI で自動実行する- 根拠: project-structure —
madgeで全パッケージの循環依存を検出し CI で exit(1)
- 根拠: project-structure —
[SHOULD]抽象インターフェースパッケージと具象実装パッケージを分離し、依存の方向を「具象 → 抽象 → コア」に統一する- 根拠: project-structure — platform, sql, ai の全ファミリーがこのパターンに従っている
[SHOULD]大規模パッケージではバレルファイル(index.ts)からの import を禁止し、サブモジュール単位の import を ESLint ルールで強制する- 根拠: project-structure —
@effect/no-import-from-barrel-packageでサブモジュール import を強制しツリーシェイキングを保証
- 根拠: project-structure —
[SHOULD]マルチバックエンドのサービス抽象化では、汎用 Tag と具象 Tag の両方を同時に提供する Layer を作成する- 根拠: extensibility-mechanisms — 全 SQL ドライバ(10+ パッケージ)が dual-tag パターンを一貫して適用
[SHOULD]プラットフォーム抽象化のインターフェースにはランタイム固有の型を含めず、フレームワーク自身の型のみで構成する- 根拠: extensibility-mechanisms —
@effect/platformのインターフェースは全て Effect/Stream/Scope 型のみで定義
- 根拠: extensibility-mechanisms —
[AVOID]モノレポ内のパッケージ間で型 import 以外の循環参照を作ること(型 import はskipTypeImports: trueで許容)- 根拠: project-structure —
madgeで値レベル循環を厳格に禁止しつつ型相互参照は許容
- 根拠: project-structure —
リソース管理と並行処理
[MUST]リソースの acquire-release ペアは不可分操作(uninterruptible 領域)で囲み、acquire 完了後のファイナライザ登録を割り込みから保護する- 根拠: concurrency-patterns —
acquireReleaseがcore.uninterruptible(core.tap(acquire, addFinalizer))で実装
- 根拠: concurrency-patterns —
[MUST]並行タスクの寿命は親タスクまたは明示的なスコープの寿命に束縛する(構造的並行処理)- 根拠: concurrency-patterns —
forkはデフォルトで親の FiberScope に子を登録し親終了時にinterruptAllChildren()を呼ぶ
- 根拠: concurrency-patterns —
[MUST]リソースのライフサイクルを持つサービスは、スコープ付き構築関数で定義し手動解放を避ける- 根拠: dependency-injection —
Layer.scopedとScopeの組み合わせでリソースはスコープ終了時に確実に解放
- 根拠: dependency-injection —
[SHOULD]ファイナライザは登録の逆順(LIFO)で実行し、リソースの依存順序を尊重する- 根拠: concurrency-patterns — Scope の
closeがファイナライザをreverse()で逆順実行
- 根拠: concurrency-patterns — Scope の
[SHOULD]並行度は個別 API に埋め込まず、統一的な concurrency パラメータとして抽象化する- 根拠: concurrency-patterns —
Concurrency型で sequential/parallel/parallelN を統一的にディスパッチ
- 根拠: concurrency-patterns —
[AVOID]グローバルスコープへのフォーク(forkDaemon相当)を安易に使わない — 明示的なライフサイクル管理が不要なケースのみに限定する- 根拠: concurrency-patterns —
forkDaemonは親の終了で interrupt されないためタスクリークを起こしうる
- 根拠: concurrency-patterns —
パフォーマンス
[MUST]ホットパスではarray.push(...spread)を避け、for ループで個別に push する- 根拠: performance-techniques — ESLint ルールでプロジェクト全体から排除。大きな配列でスタックオーバーフロー発生
[MUST]イミュータブルコレクションにバッチ更新する際は transient/mutable セッションで囲み、完了後にイミュータブルに戻す- 根拠: performance-techniques — HashMap の
beginMutation/endMutationで in-place 更新を可能にし全ファクトリメソッドが使用
- 根拠: performance-techniques — HashMap の
[SHOULD]頻繁にハッシュ比較されるオブジェクトには、初回計算時にハッシュ値をキャッシュする仕組みを設ける- 根拠: performance-techniques —
Hash.cachedで 20 以上のデータ構造にハッシュメモ化を適用
- 根拠: performance-techniques —
[SHOULD]ランタイムの中核で大量生成されるオブジェクトは、プロパティの名前と数を固定して Monomorphic Shape を維持する- 根拠: performance-techniques — EffectPrimitive の 3 スロット固定で V8 の hidden class 分裂を防止
[SHOULD]コレクションの concat/slice 操作は実際のコピーを遅延し、ロープ構造などの論理的な表現で O(1) にする- 根拠: performance-techniques — Chunk の
IConcat/ISliceタグが物理的な配列コピーをtoReadonlyArrayまで遅延
- 根拠: performance-techniques — Chunk の
[SHOULD]CJS/ESM 混在環境でシングルトンを保証するにはglobalThis上のバージョン付きストアを使う- 根拠: performance-techniques —
globalValueがSymbol.forでグローバルキーを共有しランタイム基盤の重複生成を防止
- 根拠: performance-techniques —
[AVOID]同種オブジェクトにオペレーションごとの異なるプロパティセットを持たせること(Polymorphic Shape)- 根拠: performance-techniques — V8 の hidden class 分裂によりプロパティアクセスが 10-100x の性能劣化を招く
テスト
[MUST]エフェクトフルなコードのテストには、テストランナー側でライフサイクル管理(リソース解放・ファイバー割り込み)を行う仕組みを使う- 根拠: testing-practices — テスト終了時のファイバー割り込みとリソース解放を保証し手動
runSyncのリーク防止
- 根拠: testing-practices — テスト終了時のファイバー割り込みとリソース解放を保証し手動
[MUST]テスト環境(モック時計 vs 実時間、テストランダム vs 実ランダム)は暗黙的に選択せず、各テストケースで明示的に宣言する- 根拠: testing-practices —
it.effect/it.live/it.scoped/it.scopedLiveの 4 種類を使い分けテスト環境を明確化
- 根拠: testing-practices —
[SHOULD]ドメイン固有の代数的データ型には型ガード付きのカスタムアサーション関数を提供する- 根拠: testing-practices —
assertSome/assertNone等がasserts x is Tでアサーション後の型安全を保証
- 根拠: testing-practices —
[SHOULD]バリデーションスキーマが存在する場合、プロパティベーステストの Arbitrary はスキーマから自動導出する- 根拠: testing-practices — Schema → Arbitrary の自動変換でスキーマとテストデータの整合性を保証
[SHOULD]非決定的テスト(ランダム依存・タイミング依存)はリトライラッパーで明示的にマークし、暗黙的な flaky テストを許容しない- 根拠: testing-practices —
flakyTestユーティリティでリトライ上限とタイムアウトを設定し非決定性を制御
- 根拠: testing-practices —
[SHOULD]外部依存(DB / HTTP クライアント等)はレイヤーとしてパラメータ化し、同一テストスイートを複数バックエンドで再利用する- 根拠: testing-practices —
suite(client)パターンで SQLite/LibSQL/PostgreSQL で同一テストを実行
- 根拠: testing-practices —
[AVOID]テストフレームワークの標準タイマーモックと、アプリケーションレベルの時間抽象を混在させる- 根拠: testing-practices — vitest のタイマーモックを無効化し時間制御を Effect の TestClock に一元化
コード生成と開発ワークフロー
[MUST]自動生成ファイルは生成元を編集して再生成する — 生成ファイルの直接編集を禁止し CI で差分チェック(codegen && git diff --exit-code)を実行する- 根拠: code-generation — CI で差分がないことを検証しエクスポートの不整合を防止
[MUST]ライブラリのsrc/内では自パッケージの barrel からインポートせず、直接モジュールパスを使用する- 根拠: dev-conventions — ESLint ルールで強制し循環依存防止とツリーシェイキングの確実性を保証
[SHOULD]barrel file を自動生成する場合、エントリポイントの定義をpackage.jsonのexportsやファイルシステム構造から導出する- 根拠: code-generation —
build-utils prepare-v3が exports と generateIndex 設定から barrel file を生成しモジュール追加時の更新漏れを防止
- 根拠: code-generation —
[SHOULD]フォーマッターを ESLint プラグインとして統合し、lint とフォーマットを単一コマンドで完結させる- 根拠: dev-conventions — dprint を ESLint ルールとして実行し
pnpm lint-fixだけで全スタイル修正が完了
- 根拠: dev-conventions — dprint を ESLint ルールとして実行し
[SHOULD]型テストを tstyche 等の専用ツールで記述し、型推論の正しさを回帰テストとして維持する- 根拠: dev-conventions —
dtslint/*.tst.tsで型テストを 60 以上のファイルで運用し TypeScript nightly でも日次検証
- 根拠: dev-conventions —
[SHOULD]ビルド時に純粋関数呼び出しへの/*#__PURE__*/アノテーションを自動付与し tree-shaking を最適化する- 根拠: dev-conventions —
babel-plugin-annotate-pure-callsを全パッケージのビルドステップで使用
- 根拠: dev-conventions —
[SHOULD]AST ベースの codemod には入出力ペアのインラインテストを記述し、変換の正確性を保証する- 根拠: code-generation — jscodeshift の
defineInlineTestで変換前後のコードをテスト
- 根拠: code-generation — jscodeshift の
[AVOID]コード変換に正規表現を使う — AST パーサー(jscodeshift, ts-morph 等)で構文構造を意識した変換を行う- 根拠: code-generation — JSDoc コメントの伝播やフェンス追加は jscodeshift で AST 操作し正確に動作
スキーマとバリデーション
[MUST]スキーマやバリデーションルールを定義する際は、バリデーション述語とメタデータ(エラーメッセージ、JSON Schema ヒント、説明文)を同じ定義に同梱する- 根拠: schema-validation — 全組み込みフィルタが
schemaId,title,description,jsonSchemaを述語と一緒に定義
- 根拠: schema-validation — 全組み込みフィルタが
[SHOULD]単一のデータ定義から複数の成果物を導出する場合は、中間表現(AST/IR)を定義し各成果物を AST のインタプリタとして実装する- 根拠: schema-validation — Parser/JSONSchema/Pretty/Arbitrary を独立インタプリタとして実装し
Match/getCompilerで型安全に追加
- 根拠: schema-validation — Parser/JSONSchema/Pretty/Arbitrary を独立インタプリタとして実装し
[SHOULD]AST の再帰的走査で構造共有を使い、変更がないサブツリーのオブジェクト生成を回避する- 根拠: schema-validation —
changeMapが変更なしなら元の配列を返し不要な GC 負荷を削減
- 根拠: schema-validation —
[SHOULD]コンパイル済みのインタプリタ(パーサー等)は AST ノードをキーとしてWeakMapでメモ化し、同一定義の再コンパイルを防ぐ- 根拠: schema-validation —
decodeMemoMap/encodeMemoMapがWeakMap<AST, Parser>でパーサーをキャッシュ
- 根拠: schema-validation —
[AVOID]バリデーションと型変換を同一のプリミティブで混同する — 型の絞り込み(Refinement)と型の変換(Transformation)は AST レベルで分離すべき- 根拠: schema-validation —
Refinement(型不変)とTransformation(型変化)を別のノードとして定義し走査で異なる扱いを実現
- 根拠: schema-validation —
AI エージェント設定
[MUST]AGENTS.md にはコマンドベースのバリデーション手順を記載し、各手順は実際にシェルで実行可能な形式にする- 根拠: ai-settings — 具体的コマンドを列挙し AI が解釈なしに実行できるようにしている
[MUST]自動生成ファイルを明示し、手動編集禁止と再生成コマンドをセットで記述する- 根拠: ai-settings — barrel file が自動生成であることを明記し
pnpm codegenを案内
- 根拠: ai-settings — barrel file が自動生成であることを明記し
[SHOULD]AI がコードを試行するための git 追跡外のサンドボックスディレクトリを用意する- 根拠: ai-settings — scratchpad/ が workspace に含まれつつ
.gitignoreと changeset の ignore で隔離
- 根拠: ai-settings — scratchpad/ が workspace に含まれつつ
[SHOULD]コードスタイルは「既存コードを見て学べ」と指示し、フォーマッタに任せられる部分は「完璧にしようとするな」と明示する- 根拠: ai-settings — AI のフォーマット浪費を防ぎ意味のある変更に集中させている
[SHOULD]バリデーション手順にはエラー時のリカバリ手順を含め、AI がエラーループに陥ることを防ぐ- 根拠: ai-settings —
pnpm check失敗時にpnpm cleanでキャッシュクリア後再実行のリカバリ手順を記載
- 根拠: ai-settings —
[AVOID]AGENTS.md に曖昧な品質基準(「きれいなコードを書け」等)を書くこと — 機械的に検証不可能な指示は AI の行動を制御できない- 根拠: ai-settings — 全指示がコマンド実行・具体的パターン・禁止事項の形式で記述
ルール優先度の解釈
[MUST]: 違反するとバグ・セキュリティリスク・重大な設計劣化を招くルール[SHOULD]: 従うことで品質が向上するが、文脈によっては例外を許容するルール[AVOID]: 意図的に避けるべきアンチパターン・非推奨プラクティス