Effect:TypeScript 函数式副作用框架,类型安全的异步与错误处理

Effect 是一个偏函数式(FP)的 TypeScript 框架,类似 Scala 生态的 ZIO,核心目标是用类型系统统一管理:副作用、错误处理、依赖注入和并发控制。

核心类型:Effect<A, Error, R>

Effect.Effect<User, NotFoundError, Database>

三个泛型参数分别是:

  • A — 成功时的返回值类型
  • Error — 可能抛出的错误类型(编译期已知)
  • R — 运行时需要注入的依赖环境

相比普通 async/await,错误类型不再是 unknown,依赖关系从运行时隐式变为类型系统显式。

四个核心能力

类型安全的错误处理

// 传统方式:不知道会抛什么
try {
    await fetchUser(id);
} catch (e) { }

// Effect 方式:错误类型在签名里
const fetchUser = (id: string): Effect.Effect<User, NotFoundError | DbError, Database> =>
    Effect.gen(function* () {
        const db = yield* Database;
        return yield* db.findUser(id);
    });

依赖注入

const Database = Context.Tag<Database>("Database");

// 运行时注入具体实现
Effect.runPromise(
    program.pipe(
        Effect.provide(DatabaseLive)
    )
);

并发控制

// 限制并发数为 5
await Effect.runPromise(
    Effect.all(tasks, { concurrency: 5 })
);

内置 fiber(轻量协程)、timeoutretryracecancellation,都是一等公民。

Resource 管理(自动释放)

const withDb = Effect.acquireRelease(
    Effect.sync(() => new DbConnection()),
    (conn) => Effect.sync(() => conn.close())
);

不用手写 try/finally,连接/文件/WebSocket 用完自动关闭。

基础用法示例

import { Effect, pipe } from "effect";

const program = pipe(
    Effect.succeed(1),
    Effect.map(n => n + 1),
    Effect.flatMap(n => Effect.succeed(n * 2))
);

Effect.runPromise(program).then(console.log); // 4

Generator 风格(更接近 async/await):

const program = Effect.gen(function* () {
    const a = yield* Effect.succeed(1);
    const b = yield* Effect.succeed(a + 1);
    return b * 2;
});

与其他框架对比

框架风格适合场景
Express / Hono极简快速 API
NestJSOOP + DI企业级 Web
RxJS响应式流事件流处理
EffectFP + 类型系统复杂异步系统

适合的场景

Effect 的学习曲线较陡(大量 pipe、flatMap、generator),不适合小型项目。适合:

  • 大型 Node.js 后端服务
  • AI Agent / 工作流调度系统
  • 微服务(高并发 + 复杂错误处理)
  • CLI 框架
  • 爬虫调度

核心标准:“复杂异步 + 大量错误路径”——这正是 Effect 最能体现价值的地方。如果只是 await fetch(),用 Promise 就够了。