Error Management by andrueandersoncs/claude-skill-effect-ts
npx skills add https://github.com/andrueandersoncs/claude-skill-effect-ts --skill 'Error Management'Effect 区分两种类型的故障:
Error 类型参数中表示,在编译时跟踪
2.缺陷(意外/不可恢复) - 运行时异常、错误,不在类型签名中Effect<Success, Error, Requirements>
// ^^^^^ 预期错误在此处
import { Schema, Effect } from "effect"
class UserNotFound extends Schema.TaggedError<UserNotFound>()(
"UserNotFound",
{ userId: Schema.String }
) {}
// 注意:Schema.Unknown 在这里在语义上是正确的,因为 `cause` 捕获了
// 任意捕获的异常,这些异常的类型在领域级别确实是未知的。
// 这不是类型弱化 - JavaScript 异常可以是任何值。
class NetworkError extends Schema.TaggedError<NetworkError>()(
"NetworkError",
{ cause: Schema.Unknown }
) {}
const getUser = (id: string): Effect.Effect<User, UserNotFound | NetworkError> =>
Effect.gen(function* () {
// ...实现
return yield* Effect.fail(new UserNotFound({ userId: id }))
})
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
const divide = (a: number, b: number) =>
b === 0
? Effect.fail(new DivisionByZero())
: Effect.succeed(a / b)
program.pipe(
Effect.catchAll((error) =>
Effect.succeed("回退值")
)
)
const program = getUser(id).pipe(
Effect.catchTag("UserNotFound", (error) =>
Effect.succeed(defaultUser)
),
Effect.catchTag("NetworkError", (error) =>
Effect.retry(Schedule.exponential("1 second"))
)
)
const program = getUser(id).pipe(
Effect.catchTags({
UserNotFound: (error) => Effect.succeed(defaultUser),
NetworkError: (error) => Effect.fail(new ServiceUnavailable())
})
)
const primary = fetchFromPrimary()
const fallback = fetchFromBackup()
const resilient = primary.pipe(
Effect.orElse(() => fallback)
)
const program = fetchConfig().pipe(
Effect.orElseSucceed(() => defaultConfig)
)
const program = rawApiCall().pipe(
Effect.mapError((error) => new ApiError({ cause: error }))
)
const program = effect.pipe(
Effect.mapBoth({
onError: (e) => new WrappedError({ cause: e }),
onSuccess: (a) => a.toUpperCase()
})
)
当运行多个 effect 时,收集所有错误而不是快速失败:
const results = yield* Effect.all(
[effect1, effect2, effect3],
{ mode: "either" }
)
const [failures, successes] = yield* Effect.partition(
items,
(item) => processItem(item)
)
const result = yield* Effect.validate(
[check1, check2, check3],
{ concurrency: "unbounded" }
)
缺陷是未在类型中跟踪的错误/意外故障:
const defect = Effect.die(new Error("意外错误!"))
const program = effect.pipe(Effect.orDie)
const sandboxed = Effect.sandbox(program)
Cause 类型包含完整的故障信息:
import { Cause, Match } from "effect"
// 在沙盒中,您获得完整的 Cause - 使用 Match 进行处理
const handled = Effect.sandbox(program).pipe(
Effect.catchAll((cause) =>
Match.value(cause).pipe(
Match.when(Cause.isFailure, () => {
// 预期错误
return Effect.succeed(fallback)
}),
Match.when(Cause.isDie, () => {
// 缺陷 - 记录并恢复
return Effect.succeed(fallback)
}),
Match.when(Cause.isInterrupt, () => {
// 中断
return Effect.succeed(fallback)
}),
Match.orElse(() => Effect.succeed(fallback))
)
)
)
import { Schedule } from "effect"
const resilient = effect.pipe(
Effect.retry(
Schedule.exponential("100 millis").pipe(
Schedule.jittered,
Schedule.compose(Schedule.recurs(5))
)
)
)
// 带条件的重试 - 使用 Match.tag 进行错误类型检查
const conditional = effect.pipe(
Effect.retry({
schedule: Schedule.recurs(3),
while: (error) =>
Match.value(error).pipe(
Match.tag("NetworkError", () => true),
Match.orElse(() => false)
)
})
)
const withTimeout = effect.pipe(
Effect.timeout("5 seconds")
)
const failOnTimeout = effect.pipe(
Effect.timeoutFail({
duration: "5 seconds",
onTimeout: () => new TimeoutError()
})
)
const result = yield* effect.pipe(
Effect.match({
onFailure: (error) => `失败:${error.message}`,
onSuccess: (value) => `成功:${value}`
})
)
const result = yield* effect.pipe(
Effect.matchEffect({
onFailure: (error) => logError(error).pipe(Effect.as("failed")),
onSuccess: (value) => logSuccess(value).pipe(Effect.as("success"))
})
)
catchTag 模式匹配cause 字段是典型示例(捕获的 JS 异常可以是任何值)。永远不要对可以描述其形状的字段使用 Schema.Unknown 或 Schema.Any - 而是定义适当的模式。有关全面的错误管理文档,请查阅 ${CLAUDE_PLUGIN_ROOT}/references/llms-full.txt。
搜索以下部分:
每周安装次数
0
仓库
GitHub 星标数
5
首次出现时间
1970年1月1日
安全审计
Effect distinguishes between two types of failures:
Error type parameter, tracked at compile timeEffect<Success, Error, Requirements>
// ^^^^^ Expected errors live here
import { Schema, Effect } from "effect"
class UserNotFound extends Schema.TaggedError<UserNotFound>()(
"UserNotFound",
{ userId: Schema.String }
) {}
// Note: Schema.Unknown is semantically correct here because `cause` captures
// arbitrary caught exceptions whose type is genuinely unknown at the domain level.
// This is NOT type weakening - JavaScript exceptions can be any value.
class NetworkError extends Schema.TaggedError<NetworkError>()(
"NetworkError",
{ cause: Schema.Unknown }
) {}
const getUser = (id: string): Effect.Effect<User, UserNotFound | NetworkError> =>
Effect.gen(function* () {
// ...implementation
return yield* Effect.fail(new UserNotFound({ userId: id }))
})
const divide = (a: number, b: number) =>
b === 0
? Effect.fail(new DivisionByZero())
: Effect.succeed(a / b)
program.pipe(
Effect.catchAll((error) =>
Effect.succeed("fallback value")
)
)
const program = getUser(id).pipe(
Effect.catchTag("UserNotFound", (error) =>
Effect.succeed(defaultUser)
),
Effect.catchTag("NetworkError", (error) =>
Effect.retry(Schedule.exponential("1 second"))
)
)
const program = getUser(id).pipe(
Effect.catchTags({
UserNotFound: (error) => Effect.succeed(defaultUser),
NetworkError: (error) => Effect.fail(new ServiceUnavailable())
})
)
const primary = fetchFromPrimary()
const fallback = fetchFromBackup()
const resilient = primary.pipe(
Effect.orElse(() => fallback)
)
const program = fetchConfig().pipe(
Effect.orElseSucceed(() => defaultConfig)
)
const program = rawApiCall().pipe(
Effect.mapError((error) => new ApiError({ cause: error }))
)
const program = effect.pipe(
Effect.mapBoth({
onError: (e) => new WrappedError({ cause: e }),
onSuccess: (a) => a.toUpperCase()
})
)
When running multiple effects, collect all errors instead of failing fast:
const results = yield* Effect.all(
[effect1, effect2, effect3],
{ mode: "either" }
)
const [failures, successes] = yield* Effect.partition(
items,
(item) => processItem(item)
)
const result = yield* Effect.validate(
[check1, check2, check3],
{ concurrency: "unbounded" }
)
Defects are bugs/unexpected failures not tracked in types:
const defect = Effect.die(new Error("Unexpected!"))
const program = effect.pipe(Effect.orDie)
const sandboxed = Effect.sandbox(program)
The Cause type contains complete failure information:
import { Cause, Match } from "effect"
// In sandbox, you get full Cause - use Match for handling
const handled = Effect.sandbox(program).pipe(
Effect.catchAll((cause) =>
Match.value(cause).pipe(
Match.when(Cause.isFailure, () => {
// Expected error
return Effect.succeed(fallback)
}),
Match.when(Cause.isDie, () => {
// Defect - log and recover
return Effect.succeed(fallback)
}),
Match.when(Cause.isInterrupt, () => {
// Interruption
return Effect.succeed(fallback)
}),
Match.orElse(() => Effect.succeed(fallback))
)
)
)
import { Schedule } from "effect"
const resilient = effect.pipe(
Effect.retry(
Schedule.exponential("100 millis").pipe(
Schedule.jittered,
Schedule.compose(Schedule.recurs(5))
)
)
)
// Retry with condition - use Match.tag for error type checking
const conditional = effect.pipe(
Effect.retry({
schedule: Schedule.recurs(3),
while: (error) =>
Match.value(error).pipe(
Match.tag("NetworkError", () => true),
Match.orElse(() => false)
)
})
)
const withTimeout = effect.pipe(
Effect.timeout("5 seconds")
)
const failOnTimeout = effect.pipe(
Effect.timeoutFail({
duration: "5 seconds",
onTimeout: () => new TimeoutError()
})
)
const result = yield* effect.pipe(
Effect.match({
onFailure: (error) => `Failed: ${error.message}`,
onSuccess: (value) => `Success: ${value}`
})
)
const result = yield* effect.pipe(
Effect.matchEffect({
onFailure: (error) => logError(error).pipe(Effect.as("failed")),
onSuccess: (value) => logSuccess(value).pipe(Effect.as("success"))
})
)
catchTag pattern matchingcause field on error types is the canonical example (caught JS exceptions can be any value). Never use Schema.Unknown or Schema.Any for fields whose shape you can describe - define proper schemas instead.For comprehensive error management documentation, consult ${CLAUDE_PLUGIN_ROOT}/references/llms-full.txt.
Search for these sections:
Weekly Installs
0
Repository
GitHub Stars
5
First Seen
Jan 1, 1970
Security Audits
Tailwind CSS v4 + shadcn/ui 生产级技术栈配置指南与最佳实践
2,600 周安装