| name | effect-pattern-discovery |
| description | Effect-TS patterns sourced from effect-smol reference implementation. Trigger: When implementing Effect, Layer, Schema, Pipe, Context, or error handling patterns.
|
| license | Apache-2.0 |
| metadata | {"author":"gentleman-programming","version":"1.0"} |
When to Use
- Implementing Effect-based services or layers
- Creating structured errors with Data.TaggedError or Schema.ErrorClass
- Building pipeable modules with dual functions
- Defining Context/Service patterns with Context.Tag
- Composing Layers with provide/merge
Critical Patterns
❌ FORBIDDEN: try-catch in Effect.gen
Effect.gen(function*() {
try {
return yield* someEffect
} catch (error) {
}
})
Effect.gen(function*() {
const result = yield* Effect.result(someEffect)
if (result._tag === "Failure") {
return yield* Effect.fail(handleError(result.cause))
}
return result.value
})
❌ FORBIDDEN: Type Assertions
const value = something as any
const value = something as never
const safeValue = Effect.try(() => JSON.parse(jsonString))
✅ MANDATORY: return yield* for Terminal Effects
Effect.gen(function*() {
if (invalidCondition) {
return yield* Effect.fail("Error")
}
if (shouldInterrupt) {
return yield* Effect.interrupt
}
return result
})
Code Examples
Service Definition with Context.Tag
import { Context, Effect, Layer } from "effect"
class DatabaseService extends Context.Tag("DatabaseService")<
DatabaseService,
{
readonly query: (
sql: string,
) => Effect.Effect<unknown[], DatabaseError, never>
}
>() {}
class UserService extends Context.Tag("UserService")<
UserService,
{
readonly getUser: (id: string) => Effect.Effect<User, UserError, never>
}
>() {}
const DatabaseServiceLive = Layer.succeed(
DatabaseService,
DatabaseService.of({
query: (sql) =>
Effect.tryPromise({
try: () => db.execute(sql),
catch: (e) => new DatabaseError({ cause: e }),
}),
}),
)
Structured Errors with Data.TaggedError
import { Data, Effect } from "effect"
class ValidationError extends Data.TaggedError("ValidationError")<{
field: string
message: string
}> {}
class NetworkError extends Data.TaggedError("NetworkError")<{
status: number
url: string
cause?: unknown
}> {}
const program = operation().pipe(
Effect.catchTag("ValidationError", (e) => Console.log(`Invalid field: ${e.field}`)),
)
Schema.ErrorClass for Serializable Errors
import { Schema } from "effect"
class ApiError extends Schema.ErrorClass("@effectify/ApiError")({
_tag: Schema.tag("ApiError"),
code: Schema.String,
message: Schema.String,
}) {
get message() {
return `[${this.code}] ${this.message}`
}
}
Effect.fn vs Effect.fnUntraced
| Function | Use Case | Tracing |
|---|
Effect.fn("name")(fn) | Public API, reusable | ✅ Yes |
Effect.fnUntraced(fn) | Internal hot paths | ❌ No |
Effect.gen(function*()) | One-off inline composition | Uses parent |
Dual Function Pattern
import { dual } from "effect"
export const map = dual<
<A, B>(f: (a: A) => B) => (self: Module<A>) => Module<B>,
<A, B>(self: Module<A>, f: (a: A) => B) => Module<B>
>(2, (self, f) => )
Layer Composition
const AppLayer = UserServiceLive.pipe(
Layer.provide(DatabaseServiceLive),
Layer.launch,
)
const CombinedLayer = Layer.merge(UserServiceLive, DatabaseServiceLive)
Commands
ls .effect-reference/packages/effect/src/
cat .effect-reference/packages/effect/src/internal/effect.ts
cat .effect-reference/packages/effect/src/index.ts
Resources
- effect-smol source:
.effect-reference/packages/effect/src/
- Pattern docs:
.effect-reference/.patterns/
- Error handling:
.effect-reference/.patterns/error-handling.md
- Module organization:
.effect-reference/.patterns/module-organization.md
- Library development:
.effect-reference/.patterns/effect-library-development.md