关于 effect-ts
面向使用 Effect-TS 的 TypeScript 开发者的编码指导技能,帮助按项目版本编写代码并核对 API。内容覆盖错误处理、依赖注入、并发、资源管理及其他常见开发主题。
主要功能
- 01识别 Effect v3 与 v4
- 02提供错误处理与类型建模指导
- 03指导服务与依赖注入
- 04涵盖并发和资源生命周期
- 05核对 API 并纠正常见误用
适用场景
- 01在现有项目版本中编写 Effect 代码
- 02为新项目选择适用的 v4 写法
- 03排查错误 API 或版本混用
- 04实现并发、重试或资源管理逻辑
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ tenequm/ skills --skill effect-ts安装后在 Claude Code 中输入/effect-ts确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
CHANGELOG.mdLICENSE.txtevals/evals.jsonreferences/cli.mdconcurrency.mdconfiguration.mdcore-patterns.mddatetime.mddependency-injection.mddistributed.mdeffect-ai.mderror-modeling.mdgraph.mdhttp.mdllm-corrections.mdmigration-async.mdmigration-v4.mdobservability.mdoptics.mdresource-management.mdretry-scheduling.mdrpc.mdschema.mdsql.mdstm.mdstreams.mdtesting.md详细介绍
Effect-TS
Effect 是一个 TypeScript 库,用于构建可用于生产环境的软件,提供类型化错误、结构化并发、依赖注入和内置可观测性。
版本检测
编写 Effect 代码前,先检测用户使用的版本:
# Check installed version
cat package.json | grep '"effect"'
- v4.x(推荐,也是 Effect 的发展方向):
Context.Service、Effect.catch、Effect.forkChild、Schema.TaggedErrorClass - v3.x(稳定版,目前仍常用于生产环境):
Context.Tag、Effect.catchAll、Effect.fork、Data.TaggedError
注意:v4 beta 曾短暂使用
ServiceMap模块,后于 2026-04-07(PR #1961)改回Context。如果在任何文档或较早的 beta 代码中看到ServiceMap.*,它现在对应的是Context.*。v3 和 v4 都从"effect"导入Context;其中的导出有所不同(v4 中为Context.Service,v3 中为Context.Tag)。
新项目优先使用 v4——这是 Effect 的发展方向。在现有代码库中,应与已安装的版本保持一致:除非用户提出要求,否则不要将 v3 代码改写为 v4 语法。如果确实无法确定版本,则默认使用 v4,并说明这一点。v4 仍处于 beta 阶段,因此请锁定确切版本(4.0.0-beta.x),并预期 API 偶尔会有变动。
主要文档来源
v4(主要):
- https://github.com/Effect-TS/effect-smol(v4 源码和迁移指南)
- https://github.com/Effect-TS/effect-smol/blob/main/LLMS.md(v4 大模型指南)
v3(适用于现有代码库):
- https://effect.website/docs(v3 稳定版文档)
- https://effect.website/llms.txt(大模型主题索引)
- https://effect.website/llms-full.txt(适用于大上下文的完整文档)
两个版本均适用:
AI 防护措施:关键纠正
大模型经常会生成错误的 Effect API。使用前,请对照参考文档核实每个 API。
常见幻觉(两个版本均适用):
| 错误(AI 经常生成) | 正确写法 |
|---|---|
Effect.cachedWithTTL(...) | Cache.make({ capacity, timeToLive, lookup }) |
Effect.cachedInvalidateWithTTL(...) | cache.invalidate(key) / cache.invalidateAll() |
Effect.mapError(effect, fn) | 在管道中使用 Effect.mapError(fn),或使用 Effect.catchTag |
import { Schema } from "@effect/schema" | import { Schema } from "effect"(v3.10+ 和所有 v4 版本) |
import { JSONSchema } from "@effect/schema" | import { JSONSchema } from "effect"(v3.10+) |
| JSON Schema Draft 2020-12 | Effect Schema 生成的是 Draft-07 |
| “线程局部存储” | 通过 v3 的 FiberRef / v4 的 Context.Reference 实现“纤程局部存储” |
| 纤程被“取消” | 纤程被“中断” |
| 所有队列都有背压 | 只有有界队列才有;滑动队列和丢弃队列没有 |
new MyError("message") | new MyError({ message: "..." })(Schema 错误接受对象) |
v3 特有的幻觉:
| 错误 | 正确写法(v3) |
|---|---|
Effect.Service(函数调用) | class Foo extends Effect.Service<Foo>()("id", {}) |
Effect.match(effect, { ... }) | Effect.match(effect, { onSuccess, onFailure }) |
Effect.provide(layer1, layer2) | Effect.provide(Layer.merge(layer1, layer2)) |
v4 特有的幻觉(AI 可能会混淆 v3 和 v4):
| 错误(在 v4 代码中使用 v3 API) | 正确(v4) |
|---|---|
Context.Tag("X")(v3 形式) | Context.Service<X>(id) 或类语法 |
ServiceMap.Service / ServiceMap.Reference | 2026-04-07 更名回 Context.Service / Context.Reference |
Effect.catchAll(fn) | Effect.catch(fn) |
Effect.fork(effect) | Effect.forkChild(effect) |
Effect.forkDaemon(effect) | Effect.forkDetach(effect) |
Data.TaggedError | Schema.TaggedErrorClass |
FiberRef.get(ref) | yield* References.X(一个 Context.Reference) |
yield* ref(将 Ref 作为 Effect) | yield* Ref.get(ref)(Ref 不再是 Effect) |
yield* fiber(将 Fiber 作为 Effect) | yield* Fiber.join(fiber)(Fiber 不再是 Effect) |
Logger.Default / Logger.Live | Logger.layer(v4 命名约定) |
Schema.TaggedError | Schema.TaggedErrorClass |
Schema.makeUnsafe(input) | Schema.make(input)(会抛出 SchemaError);还有实例方法 schema.makeOption(...)、schema.makeEffect(...) |
ParseResult(来自 "effect") | SchemaIssue 模块 + SchemaError 类;使用 Schema.isSchemaError 进行类型收窄 |
HttpApiEndpoint.get(n, p).pipe(HttpApiEndpoint.setPath(...), setPayload(...), setSuccess(...)) | HttpApiEndpoint.get(n, p, { params, query, payload, success, error })(对象选项形式) |
Otlp.layer({ url, serviceName }) | OtlpTracer.layer({ url, resource: { serviceName } }) + OtlpSerialization.layerJson + FetchHttpClient.layer |
import { HttpApi } from "@effect/platform"(v4) | import { HttpApi } from "effect/unstable/httpapi" |
| HttpApi 端点的 Schema 错误默认是类型化错误 | 在当前 v4 测试版中,除非经过转换,否则默认是缺陷 |
请阅读 references/llm-corrections.md,查看完整的修正表。
渐进式披露
只阅读与你的任务相关的参考文件:
- 错误建模或类型化失败 →
references/error-modeling.md - 服务、DI 或 Layer 接线 →
references/dependency-injection.md - 按键动态 Layer(按租户划分的资源、
LayerMap)→references/dependency-injection.md - 将 Effect 接入非 Effect 框架(Hono/Express、
ManagedRuntime)→references/dependency-injection.md - 重试、超时或退避 →
references/retry-scheduling.md - Fiber、分叉或并行工作 →
references/concurrency.md - 请求批处理、消除 N+1、DataLoader 模式 →
references/concurrency.md - 多提供方回退(
ExecutionPlan)→references/effect-ai.md/references/retry-scheduling.md - 流、队列或 SSE →
references/streams.md - 流分帧(NDJSON / MessagePack 编解码)→
references/streams.md - 运行子进程 / 调用 shell →
references/concurrency.md - 资源生命周期或清理 →
references/resource-management.md - 可刷新值(轮换凭据、轮询配置)→
references/resource-management.md - 引用计数的共享资源(
RcRef/RcMap)→references/resource-management.md - Schema 验证或解码 →
references/schema.md - 品牌类型 / 名义类型(
Brand)→references/schema.md - 日志、指标或追踪 →
references/observability.md - HTTP 客户端或 API 调用 →
references/http.md - HTTP API 服务端 →
references/http.md(涵盖客户端和服务端) - 文件上传 / multipart 表单数据 →
references/http.md - LLM/AI 集成 →
references/effect-ai.md - 配置、环境变量、密钥 →
references/configuration.md - SQL / 数据库访问 →
references/sql.md - 命令行应用 →
references/cli.md - 类型化客户端/服务端 RPC →
references/rpc.md - 分片实体、持久化工作流、事件溯源 →
references/distributed.md - 事务状态(STM、
Tx*)→references/stm.md - 日期/时间处理 →
references/datetime.md - 不可变嵌套更新(optics)→
references/optics.md - 图、依赖排序、最短路径、环检测 →
references/graph.md - 模式匹配(
Match)→references/core-patterns.md - 资源池化(
Pool)→references/resource-management.md - Fiber 集合、SubscriptionRef、工作线程 →
references/concurrency.md - 测试 Effect 代码 →
references/testing.md - 基于属性的测试 / 根据 Schema 生成数据 →
references/testing.md - 从 async/await 迁移 →
references/migration-async.md - 从 v3 迁移到 v4 →
references/migration-v4.md - 核心类型、gen、pipe、运行 →
references/core-patterns.md - 完整的错误用法与正确用法 API 表 →
references/llm-corrections.md
核心工作流
- 检测版本:编写任何代码之前,先检查
package.json - 明确边界:确定 IO 发生的位置,并将核心逻辑保留为
Effect值 - 选择风格:顺序逻辑使用
Effect.gen,简单转换使用管道。在 v4 中,命名函数优先使用Effect.fn("name") - 显式建模错误:在
E通道中为预期错误标注类型;将 Bug 视为缺陷 - 建模依赖:使用服务和层;接口中不要包含构造逻辑
- 管理资源:打开/关闭文件、连接等资源时使用
Scope - 提供层,并仅在程序边界处运行 Effect(
NodeRuntime.runMain或ManagedRuntime) - 使用前确认 API 存在——查阅 https://tim-smart.github.io/effect-io-ai/ 或源文档
入门函数集
从这约 20 个函数开始(官方推荐集):
创建 Effect: Effect.succeed、Effect.fail、Effect.sync、Effect.tryPromise
组合: Effect.gen(v4 中还包括 Effect.fn)、Effect.andThen、Effect.map、Effect.tap、Effect.all
运行: Effect.runPromise、NodeRuntime.runMain(入口点首选)
错误处理: Effect.catchTag、Effect.catch(v4)/ Effect.catchAll(v3)、Effect.orDie
资源: Effect.acquireRelease、Effect.acquireUseRelease、Effect.scoped
依赖项: Effect.provide、Effect.provideService
关键模块: Effect、Schema、Layer、Option、Result(v4)/ Either(v3)、Array、Match
DI(v4): Context.Service、Context.Reference、Layer.effect、Effect.fn("name")
DI(v3): Context.Tag、Context.Reference
导入模式
始终从 "effect" 使用聚合导入:
import { Context, Effect, Schema, Layer, Option, Stream } from "effect"
对于配套软件包,从软件包名称导入。v3 和 v4 在此处有所不同:
// v4 (recommended) - platform transports still separate, but HttpApi / observability
// moved under effect/unstable/*
import { NodeRuntime } from "@effect/platform-node"
import { FetchHttpClient } from "effect/unstable/http"
import { HttpApi, HttpApiEndpoint, HttpApiGroup, HttpApiBuilder, HttpApiScalar } from "effect/unstable/httpapi"
import { OtlpLogger, OtlpSerialization, OtlpTracer } from "effect/unstable/observability"
// v3 (stable) companion packages
import { NodeRuntime } from "@effect/platform-node"
import { HttpClient } from "@effect/platform"
import { NodeSdk } from "@effect/opentelemetry"
除非打包工具需要通过深层模块导入(effect/Effect)来进行 tree-shaking,否则应避免这样做。
输出规范
- 在每个代码示例中展示导入语句
- 多步骤逻辑优先使用
Effect.gen(命令式);转换优先使用管道 - 在 v4 中,命名函数使用
Effect.fn("name"),而不是裸用Effect.gen;内部辅助函数若不需要 span/stack-frame,则使用Effect.fnUntraced - 库代码中绝不调用
Effect.runPromise/Effect.runSync——仅在程序边界处调用 - CLI/服务入口点使用
NodeRuntime.runMain(可优雅处理 SIGINT) - 将 Effect 集成到非 Effect 框架(Hono、Express 等)时,使用
ManagedRuntime - 在生成器中引发错误时,始终使用
return yield*(确保 TS 理解控制流) - 避免 point-free/tacit 用法:写成
Effect.map((x) => fn(x),而不是Effect.map(fn)(泛型会被擦除) - 明确保持依赖关系图(服务、层、标签)
- 有助于设计决策时,说明
Effect<A, E, R>的形状
Agent 质量检查清单
输出 Effect 代码前,请核对:
- 每个 API 均存在(对照 tim-smart API 列表或源文档检查)
- 导入来自
"effect"(而非@effect/schema、@effect/io等) - 版本与用户的代码库一致(v3 与 v4 语法)
- 预期错误已在
E中进行类型标注;意外失败属于缺陷 - 仅在程序边界处调用
run*,而非在库代码中调用 - 使用
acquireRelease打开的资源均包装在Effect.scoped中 - 运行前已提供层(没有缺失的
R要求) - 生成器主体使用
yield*(而非不带*的yield) - 在生成器中引发错误时使用
return yield*模式