已发布 上游基线 bf46254 原文 ↗ 在 GitHub 编辑

可 yield 的错误

定义可以直接在 Effect.gen 中被 yield 的自定义错误。

Data.ErrorData.TaggedError 创建的错误是可 yield 的。在 Effect.gen 内部,yield 其中一个错误等价于把它传给 Effect.fail

Data.Error

当错误不需要判别标签(discriminant tag)时,请使用 Data.Error

示例(yield 一个自定义错误)

import { Data, Effect, Exit } from "effect"

class InvalidInput extends Data.Error<{
  readonly message: string
}> {}

const program = Effect.gen(function* () {
  return yield* new InvalidInput({ message: "Name is required" })
})

Effect.runSyncExit(program) // => Exit.fail(new InvalidInput({ message: "Name is required" }))

Data.TaggedError

Data.TaggedError 会额外添加一个只读的 _tag 字段。tagged error 构成可判别联合类型(discriminated union),可以用 Effect.catchTagEffect.catchTags 精确处理。

示例(处理 tagged error)

import { Data, Effect } from "effect"

class NotFound extends Data.TaggedError("NotFound")<{
  readonly id: string
}> {}

class PermissionDenied extends Data.TaggedError("PermissionDenied")<{
  readonly id: string
}> {}

const loadUser = (
  id: string,
): Effect.Effect<string, NotFound | PermissionDenied> =>
  Effect.gen(function* () {
    if (id === "missing") {
      return yield* new NotFound({ id })
    }
    return `user:${id}`
  })

const program = loadUser("missing").pipe(
  Effect.catchTag("NotFound", (error) => Effect.succeed(`No user ${error.id}`)),
)

Effect.runSync(program) // => "No user missing"

对于调用方可能需要区分的领域错误,请使用 tagged error。这个类既是该错误的构造函数,也是它的 TypeScript 类型。

Tags Must Be Unique

Effect.catchTag 通过比较 _tag 字符串来匹配错误,TypeScript 也以同样的方式收窄联合类型。这两种机制都假定每个 tagged error 使用唯一的标签,但 TypeScript 无法强制这一点:没有什么能阻止两个类把同一个标签字符串传给 Data.TaggedError。一旦出现这种情况,这两个错误就无法区分,Effect.catchTagEffect.catchTags 会把两者都捕获,而编译器和运行时都不会给出任何警告。