Effect 深度课effect@4.1.4 · LTS
核心值与组合

L05 构造子全景:把现实世界装进 Effect

⏱ 25 min难度 2/5前置:L04
本课目标
  • 按场景选对构造子
  • 区分可恢复错误与缺陷的构造方式
前置课时尚未完成:L04

可以自行跳转学习,但按顺序推进会更省力;学情分析会把这类缺口归入「前置缺口」。

常用构造子
← 代码可左右滑动 →
import { Effect } from "effect"

Effect.succeed(42)                 // 已有值
Effect.fail(new NotFound())         // 预期错误,进入 E 通道
Effect.sync(() => Date.now())       // 同步副作用,假定不抛
Effect.try(() => JSON.parse(s))     // 同步副作用 + 映射异常
Effect.promise(() => fetch(url))    // 不抛的异步
Effect.tryPromise({                // 异步 + 显式映射异常
  try: () => fetch(url),
  catch: () => new HttpError()
})
Effect.die("impossible state")     // 缺陷 defect,不进 E 通道
Effect.void                        // 成功但无有用值
Effect.log("hello")                // 结构化日志
Effect.sleep("200 millis")         // 可中断的等待
💡 try / tryPromise 是把「不受控异常」收敛成「有名字的预期错误」的主要入口。

为什么要有 die

有些失败不是业务分支,而是程序写错了:断言失败、不可能的状态、第三方库的 bug。它们不该被 domain 逻辑 catch 掉,也不该污染 E 类型。Effect.die 把它们放进 Cause 的 Die reason,由应用边界统一报告。

💡 选择顺序

先问「调用方需要为这个失败做决策吗?」需要 → Effect.fail / tryPromise 的 catch;不需要、代表 bug → Effect.die 或让异常自然变成 defect。

交互演练
关键术语
defect
意外的、代表 bug 的失败,不参与类型化恢复
预期错误 failure
E 通道中列出的、调用方应处理的失败
常见误区
× 到处用 tryPromise 把真 bug 也吞成业务错误,导致错误永远被「恢复」掉。
随堂测验(即时反馈,答题计入掌握度)
Q1把一个「缓存未命中」建模成什么最合适?
Q2Effect.die 产生的失败在哪里?