effect

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Effect-TS Best Practices

Effect-TS 最佳实践

Opinionated patterns for Effect-TS codebases. Effect provides typed functional programming with composable errors, dependency injection, and observability.
针对 Effect-TS 代码库的约定式模式。Effect 提供具备可组合错误处理、依赖注入和可观测性的类型化函数式编程能力。

Critical Rules

核心规则

  1. NEVER use
    any
    or type casts (
    as Type
    )
    - Use
    Schema.make()
    for branded types,
    Schema.decodeUnknown()
    for parsing
  2. Don't use
    catchAll
    when error type is
    never
    - No errors to catch
  3. Never use global
    Error
    in Effect channels
    - Use
    Schema.TaggedError
    for domain errors
  4. Ban
    { disableValidation: true }
    - Lint against this
  5. Don't wrap safe operations in Effect - Only use
    Effect.try()
    for throwing operations
  6. Use
    mapError
    not
    catchAllCause
    - Distinguish expected errors from bugs
  7. Never silently swallow errors - Failures MUST be visible in the Effect's error channel E
  1. 绝对不要使用
    any
    或类型断言(
    as Type
    - 使用
    Schema.make()
    创建品牌类型,使用
    Schema.decodeUnknown()
    进行解析
  2. 当错误类型为
    never
    时,不要使用
    catchAll
    - 没有需要捕获的错误
  3. 绝对不要在Effect通道中使用全局
    Error
    - 针对领域错误使用
    Schema.TaggedError
  4. 禁止使用
    { disableValidation: true }
    - 通过Lint规则禁用该选项
  5. 不要将安全操作包裹在Effect中 - 仅对可能抛出异常的操作使用
    Effect.try()
  6. 使用
    mapError
    而非
    catchAllCause
    - 区分预期错误与程序缺陷
  7. 绝对不要静默吞掉错误 - 失败必须在Effect的错误通道E中可见

Quick Reference

快速参考

PatternDON'TDO
Service definition
Context.Tag
Effect.Service
with
dependencies
array
Error typesGeneric
Error
Schema.TaggedError
with context fields
Branded IDsRaw
string
Schema.String.pipe(Schema.brand("@Ns/Entity"))
Running effects
runSync
/
runPromise
in services
Return
Effect
, run at edge
Logging
console.log
Effect.log
with structured data
Configuration
process.env
Config
with validation
Method tracingManual spans
Effect.fn("Service.method")
Nullable results
null
/
undefined
Option
types
StateMutable variables
Ref
Time
Date.now()
,
new Date()
Clock
service
模式不要做要做
服务定义
Context.Tag
dependencies
数组的
Effect.Service
错误类型通用
Error
带上下文字段的
Schema.TaggedError
品牌化ID原生
string
Schema.String.pipe(Schema.brand("@Ns/Entity"))
运行Effect在服务中使用
runSync
/
runPromise
返回
Effect
,在边缘层运行
日志
console.log
带结构化数据的
Effect.log
配置
process.env
带验证的
Config
方法追踪手动Span
Effect.fn("Service.method")
可空结果
null
/
undefined
Option
类型
状态可变变量
Ref
时间
Date.now()
new Date()
Clock
服务

Service Pattern

服务模式

typescript
class UserService extends Effect.Service<UserService>()("UserService", {
  dependencies: [DatabaseService.Default],
  effect: Effect.gen(function* () {
    const db = yield* DatabaseService

    return {
      findById: Effect.fn("UserService.findById")(
        (id: UserId) => db.query(/* ... */)
      ),
    }
  }),
}) {}

// Usage - dependencies auto-provided
UserService.findById(userId)
typescript
class UserService extends Effect.Service<UserService>()("UserService", {
  dependencies: [DatabaseService.Default],
  effect: Effect.gen(function* () {
    const db = yield* DatabaseService

    return {
      findById: Effect.fn("UserService.findById")(
        (id: UserId) => db.query(/* ... */)
      ),
    }
  }),
}) {}

// 使用方式 - 自动提供依赖
UserService.findById(userId)

Error Handling

错误处理

typescript
// Define domain-specific errors
class UserNotFoundError extends Schema.TaggedError<UserNotFoundError>()(
  "UserNotFoundError",
  { userId: UserId, message: Schema.String }
) {}

// Handle with catchTag (preserves type info)
effect.pipe(
  Effect.catchTag("UserNotFoundError", (e) => /* handle */),
  Effect.catchTag("AuthExpiredError", (e) => /* handle */)
)
typescript
// 定义领域专属错误
class UserNotFoundError extends Schema.TaggedError<UserNotFoundError>()(
  "UserNotFoundError",
  { userId: UserId, message: Schema.String }
) {}

// 使用catchTag处理(保留类型信息)
effect.pipe(
  Effect.catchTag("UserNotFoundError", (e) => /* 处理逻辑 */),
  Effect.catchTag("AuthExpiredError", (e) => /* 处理逻辑 */)
)

Schema Pattern

模式定义

typescript
// Branded ID
const UserId = Schema.String.pipe(Schema.brand("@App/UserId"))

// Domain entity with Schema.Class
class User extends Schema.Class<User>("User")({
  id: UserId,
  email: Schema.String,
  createdAt: Schema.DateFromSelf,
}) {
  get displayName() { return this.email.split("@")[0] }
}
typescript
// 品牌化ID
const UserId = Schema.String.pipe(Schema.brand("@App/UserId"))

// 基于Schema.Class的领域实体
class User extends Schema.Class<User>("User")({
  id: UserId,
  email: Schema.String,
  createdAt: Schema.DateFromSelf,
}) {
  get displayName() { return this.email.split("@")[0] }
}

Layer Composition

层组合

typescript
// Declare dependencies in service, not at usage
const MainLayer = Layer.mergeAll(
  UserServiceLive,
  AuthServiceLive,
  DatabaseLive
)

// Run program
Effect.runPromise(program.pipe(Effect.provide(MainLayer)))
typescript
// 在服务中声明依赖,而非在使用时
const MainLayer = Layer.mergeAll(
  UserServiceLive,
  AuthServiceLive,
  DatabaseLive
)

// 运行程序
Effect.runPromise(program.pipe(Effect.provide(MainLayer)))

Detailed Guides

详细指南

  • Anti-Patterns - Forbidden patterns with fixes
  • Error Patterns - Domain errors, rich context, HTTP mapping
  • Schema Patterns - Branded types, transforms, validation
  • Service Patterns - Effect.Service, dependency injection
  • Layer Patterns - Composition, memoization, testing
  • Observability Patterns - Logging, tracing, metrics
  • SQL Patterns - Database integration, transactions
  • Testing Patterns - effect-vitest, property testing, Testcontainers
  • Atom Patterns - React state management with Effect
  • RPC & Cluster Patterns - Distributed systems
  • 反模式 - 包含修复方案的禁用模式
  • 错误模式 - 领域错误、丰富上下文、HTTP映射
  • 模式定义 - 品牌类型、转换、验证
  • 服务模式 - Effect.Service、依赖注入
  • 层模式 - 组合、记忆化、测试
  • 可观测性模式 - 日志、追踪、指标
  • SQL模式 - 数据库集成、事务
  • 测试模式 - effect-vitest、属性测试、Testcontainers
  • Atom模式 - 结合Effect的React状态管理
  • RPC与集群模式 - 分布式系统