关于 effect-ts-anti-patterns
一份 Effect-TS 代码审查与调试参考,帮助识别可能导致资源泄漏、崩溃或未处理错误的常见误用,面向使用 Effect-TS 的开发者,不适用于普通 TypeScript 或其他函数式库。
主要功能
- 01说明常见 Effect-TS 反模式
- 02展示更安全的 Effect 组合
- 03涵盖类型化错误处理
- 04指导限制并发
- 05介绍可安全中断的资源清理
- 06列出代码审查警示项
适用场景
- 01审查 Effect-TS 代码
- 02排查未处理的 Promise 拒绝
- 03避免过量并发任务
- 04检查资源清理与错误处理路径
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ mrevanzak/ effect-ts-skills --skill effect-ts-anti-patterns安装后在 Claude Code 中输入/effect-ts-anti-patterns确认已加载。
详细介绍
Effect-TS 反模式
概述
Effect-TS 提供了强大的函数式框架,但常见的命令式习惯可能绕过其安全保障。本技能会识别并修复导致资源泄漏、进程崩溃和未处理错误的模式。
适用场景
- 在审查 Effect-TS 实现的代码时。
- 在调试 Effect 代码中的“未处理的 Promise 拒绝”或进程崩溃时。
- 在优化并行操作的性能时。
不适用场景:
- 对于简单的非 Effect TypeScript 代码。
- 使用其他函数式库(如 fp-ts 等)时。
反模式参考
| 反模式 | 错误代码 | 正确代码 | 原因 |
|---|---|---|---|
| 在边界之外运行 | 函数中途执行 await Effect.runPromise(fx) | yield* fx(组合) | 绕过错误通道和追踪。 |
缺少 yield* | const user = yield fetchUser() | const user = yield* fetchUser() | 生成的是 Effect 对象,而不是结果。 |
| 抛出错误 | if (!ok) throw new Error() | yield* Effect.fail(new Error()) | throw 会创建“缺陷”(导致崩溃),而不是类型化错误。 |
| 无界并行 | Effect.all(tasks)(默认) | Effect.all(tasks, { concurrency: 10 }) | 防止内存溢出和速率限制耗尽。 |
| 忽略错误 | Effect.runPromise(fx)(无捕获) | fx.pipe(Effect.catchAll(...)) | 会导致未处理的拒绝。 |
| 手动清理 | try { ... } finally { cleanup() } | Effect.acquireRelease(...) | finally 无法保证在中断时执行清理。 |
常见错误
1. yield 与 yield* 的陷阱
// ❌ BAD: Missing *, yields the Effect object itself
const bad = Effect.gen(function* () {
const user = yield fetchUser(id); // Returns Effect, not User!
});
// ✅ GOOD: yield* executes the Effect
const good = Effect.gen(function* () {
const user = yield* fetchUser(id); // Returns User
});
2. 无界并行
// ❌ BAD: 10,000 concurrent requests (OOM risk)
const bad = Effect.all(urls.map(fetch));
// ✅ GOOD: Bounded to 10 concurrent
const good = Effect.all(urls.map(fetch), { concurrency: 10 });
3. 在代码中途运行 Effect
// ❌ BAD: Effect.runPromise scattered throughout
const bad = async () => {
const user = await Effect.runPromise(getUser(id));
const posts = await Effect.runPromise(getPosts(user.id));
};
// ✅ GOOD: Compose effects, run ONCE at boundary
const good = Effect.gen(function* () {
const user = yield* getUser(id);
const posts = yield* getPosts(user.id);
return { user, posts };
});
合理化说辞对照表
| 借口 | 事实 |
|---|---|
“我会用 concurrency: 'unbounded' 来提速” | 快 = 崩溃。处理外部资源时始终要限制并行度。 |
“我先直接 throw 吧” | throw 会绕过错误通道,使代码无法测试。 |
| “在这里运行更简单” | 在代码中途运行会丢失上下文和追踪,也无法确保中断安全。 |
危险信号
- 在循环或辅助函数中使用
Effect.runPromise或Effect.runSync。 - 对大型列表使用
Effect.all时未设置concurrency选项。 - 在
Effect.gen代码块中使用throw关键字。 - 调用 Effect 时使用
yield而不加*。
交叉引用
- 必备背景知识: effect-ts-fundamentals
- 必备子技能: effect-ts-concurrency
- 参考: effect-ts-resources
评论
支持 Markdown