> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/Effect-TS/tsgo/llms.txt
> Use this file to discover all available pages before exploring further.

# Style diagnostics

> Diagnostics that enforce idiomatic Effect patterns, cleanup, and consistency across your codebase.

Style diagnostics suggest code improvements that make Effect code more idiomatic, concise, and consistent. Most include a quick fix (🔧) so the improvement is one keystroke away. All are suggestions or off by default — they never block compilation.

<Info>
  Rules marked 💡 are suggestions. Rules marked ➖ are off by default and must be enabled in `diagnosticSeverity`.
</Info>

<AccordionGroup>
  <Accordion title="catchAllToMapError — 💡 suggestion + 🔧 quick fix">
    **V3/V4:** ✓ / ✓

    Suggests using `Effect.mapError` instead of the pattern `Effect.catchAll(e => Effect.fail(transform(e)))`. When you only need to transform the error type without recovering, `mapError` is the idiomatic choice.

    ```typescript theme={null}
    import { Effect } from "effect"

    // ❌ Before — verbose catch + fail pattern
    const result = someEffect.pipe(
      Effect.catchAll((e) => Effect.fail(new WrappedError({ cause: e })))
    )

    // ✅ After (quick fix applied) — concise mapError
    const result = someEffect.pipe(
      Effect.mapError((e) => new WrappedError({ cause: e }))
    )
    ```
  </Accordion>

  <Accordion title="deterministicKeys — ➖ off by default + 🔧 quick fix">
    **V3/V4:** ✓ / ✓

    Enforces deterministic, file-path-based naming for service identifiers, tag identifiers, and error tag strings. Consistent key naming prevents accidental collisions when the same identifier is used in different files. Configure the naming formula with `keyPatterns` in the plugin options.

    ```typescript theme={null}
    import { Effect } from "effect"

    // ❌ Violation (when enabled) — key does not follow the configured pattern
    class Database extends Effect.Service<Database>()("DB", {
      effect: Effect.succeed({ query: () => Effect.void })
    }) {}

    // ✅ After quick fix — key matches the deterministic formula
    class Database extends Effect.Service<Database>()("services/Database", {
      effect: Effect.succeed({ query: () => Effect.void })
    }) {}
    ```

    To enable:

    ```jsonc theme={null}
    { "diagnosticSeverity": { "deterministicKeys": "warning" } }
    ```
  </Accordion>

  <Accordion title="effectFnOpportunity — 💡 suggestion + 🔧 quick fix">
    **V3/V4:** ✓ / ✓

    Suggests wrapping functions that return an `Effect` with `Effect.fn` to get automatic tracing, span naming, and a cleaner call signature. Applies to function declarations and arrow functions at module scope.

    ```typescript theme={null}
    import { Effect } from "effect"

    // ❌ Before — plain function returning Effect
    const getUser = (id: string) =>
      Effect.gen(function* () {
        const db = yield* Database
        return yield* db.findById(id)
      })

    // ✅ After (quick fix applied) — wrapped with Effect.fn for tracing
    const getUser = Effect.fn("getUser")((id: string) =>
      Effect.gen(function* () {
        const db = yield* Database
        return yield* db.findById(id)
      })
    )
    ```
  </Accordion>

  <Accordion title="effectMapVoid — 💡 suggestion + 🔧 quick fix">
    **V3/V4:** ✓ / ✓

    Suggests using `Effect.asVoid` instead of `Effect.map(() => void 0)`, `Effect.map(() => undefined)`, or `Effect.map(() => {})`. `Effect.asVoid` is the idiomatic way to discard a success value.

    ```typescript theme={null}
    import { Effect } from "effect"

    // ❌ Before — verbose map to void
    const result = someEffect.pipe(
      Effect.map(() => void 0)
    )

    // ✅ After (quick fix applied)
    const result = someEffect.pipe(
      Effect.asVoid
    )
    ```
  </Accordion>

  <Accordion title="effectSucceedWithVoid — 💡 suggestion + 🔧 quick fix">
    **V3/V4:** ✓ / ✓

    Suggests using `Effect.void` instead of `Effect.succeed(undefined)` or `Effect.succeed(void 0)`. `Effect.void` is the canonical empty-success value.

    ```typescript theme={null}
    import { Effect } from "effect"

    // ❌ Before
    const noop = Effect.succeed(undefined)

    // ✅ After (quick fix applied)
    const noop = Effect.void
    ```
  </Accordion>

  <Accordion title="missedPipeableOpportunity — ➖ off by default + 🔧 quick fix">
    **V3/V4:** ✓ / ✓

    Suggests converting deeply nested function calls to `.pipe()` style for better readability. Triggers when at least `pipeableMinArgCount` (default: 2) contiguous pipeable transformations are nested.

    ```typescript theme={null}
    import { Effect } from "effect"

    // ❌ Before — nested calls, hard to read
    const result = Effect.mapError(
      Effect.map(someEffect, (x) => x + 1),
      (e) => new WrappedError({ cause: e })
    )

    // ✅ After (quick fix applied) — pipe style
    const result = someEffect.pipe(
      Effect.map((x) => x + 1),
      Effect.mapError((e) => new WrappedError({ cause: e }))
    )
    ```

    To enable:

    ```jsonc theme={null}
    { "diagnosticSeverity": { "missedPipeableOpportunity": "suggestion" } }
    ```
  </Accordion>

  <Accordion title="missingEffectServiceDependency — ➖ off by default (V3 only)">
    **V3 only**  ·  **V4:** —

    Checks that an `Effect.Service` class's declared `dependencies` array satisfies all required layer inputs. If a service's implementation requires another service but that service is not listed in `dependencies`, the layer will be incomplete.

    ```typescript theme={null}
    import { Effect } from "effect"

    class Config extends Effect.Service<Config>()("Config", {
      effect: Effect.succeed({ url: "http://localhost" })
    }) {}

    // ❌ Violation (when enabled) — Config is required but not in dependencies
    class HttpClient extends Effect.Service<HttpClient>()("HttpClient", {
      effect: Effect.gen(function* () {
        const config = yield* Config
        return { get: () => Effect.void }
      }),
      // dependencies: [Config.Default] // missing!
    }) {}

    // ✅ Correct — Config.Default listed in dependencies
    class HttpClient extends Effect.Service<HttpClient>()("HttpClient", {
      effect: Effect.gen(function* () {
        const config = yield* Config
        return { get: () => Effect.void }
      }),
      dependencies: [Config.Default]
    }) {}
    ```

    To enable:

    ```jsonc theme={null}
    { "diagnosticSeverity": { "missingEffectServiceDependency": "warning" } }
    ```
  </Accordion>

  <Accordion title="redundantSchemaTagIdentifier — 💡 suggestion + 🔧 quick fix">
    **V3/V4:** ✓ / ✓

    Suggests removing the redundant identifier argument from `Schema.TaggedClass`, `Schema.TaggedError`, and `Schema.TaggedRequest` when the identifier is the same as the class name. The class name is used by default, so passing it explicitly is noise.

    ```typescript theme={null}
    import { Schema } from "effect"

    // ❌ Before — identifier duplicates the class name
    class UserNotFound extends Schema.TaggedError<UserNotFound>()("UserNotFound", {
      id: Schema.String
    }) {}

    // ✅ After (quick fix applied) — identifier removed
    class UserNotFound extends Schema.TaggedError<UserNotFound>()({
      id: Schema.String
    }) {}
    ```
  </Accordion>

  <Accordion title="schemaStructWithTag — 💡 suggestion + 🔧 quick fix">
    **V3/V4:** ✓ / ✓

    Suggests replacing `Schema.Struct` with a `_tag` field with `Schema.TaggedStruct`. `Schema.TaggedStruct` makes the `_tag` field optional in the constructor (it defaults to the tag value), reducing boilerplate.

    ```typescript theme={null}
    import { Schema } from "effect"

    // ❌ Before — Schema.Struct with explicit _tag
    const UserEvent = Schema.Struct({
      _tag: Schema.Literal("UserEvent"),
      userId: Schema.String,
    })

    // ✅ After (quick fix applied) — Schema.TaggedStruct
    const UserEvent = Schema.TaggedStruct("UserEvent", {
      userId: Schema.String,
    })
    ```
  </Accordion>

  <Accordion title="schemaUnionOfLiterals — ➖ off by default + 🔧 quick fix (V3 only)">
    **V3 only**  ·  **V4:** —

    Suggests combining multiple `Schema.Literal` calls inside a `Schema.Union` into a single `Schema.Literal` call. A single `Schema.Literal` with multiple arguments is equivalent and more concise.

    ```typescript theme={null}
    import { Schema } from "effect"

    // ❌ Before — multiple Literal in Union
    const Status = Schema.Union(
      Schema.Literal("active"),
      Schema.Literal("inactive"),
      Schema.Literal("pending")
    )

    // ✅ After (quick fix applied) — single Literal
    const Status = Schema.Literal("active", "inactive", "pending")
    ```

    To enable:

    ```jsonc theme={null}
    { "diagnosticSeverity": { "schemaUnionOfLiterals": "suggestion" } }
    ```
  </Accordion>

  <Accordion title="serviceNotAsClass — ➖ off by default + 🔧 quick fix (V4 only)">
    **V4 only**  ·  **V3:** —

    Warns when `ServiceMap.Service` is used as a variable expression instead of a class declaration. The class declaration form is the idiomatic V4 pattern and enables better type inference, tooling support, and accessor generation.

    ```typescript theme={null}
    import { ServiceMap } from "effect"

    // ❌ Violation (when enabled) — variable assignment form
    const Database = ServiceMap.Service<Database>()("Database", {
      effect: Effect.succeed({ query: () => Effect.void })
    })

    // ✅ After quick fix — class declaration form
    class Database extends ServiceMap.Service<Database>()("Database", {
      effect: Effect.succeed({ query: () => Effect.void })
    }) {}
    ```

    To enable:

    ```jsonc theme={null}
    { "diagnosticSeverity": { "serviceNotAsClass": "warning" } }
    ```
  </Accordion>

  <Accordion title="strictBooleanExpressions — ➖ off by default">
    **V3/V4:** ✓ / ✓

    Enforces that only strictly `boolean` values are used in conditional expressions. Disallows truthy/falsy coercion of strings, numbers, `null`, and `undefined` in conditions. Mirrors TypeScript's `strictNullChecks` spirit for conditionals.

    ```typescript theme={null}
    // ❌ Violation (when enabled) — number used in condition (truthy coercion)
    const count = getCount()
    if (count) { // count is number, not boolean
      processItems()
    }

    // ✅ Correct — explicit boolean comparison
    const count = getCount()
    if (count > 0) {
      processItems()
    }
    ```

    To enable:

    ```jsonc theme={null}
    { "diagnosticSeverity": { "strictBooleanExpressions": "warning" } }
    ```
  </Accordion>

  <Accordion title="unnecessaryEffectGen — 💡 suggestion + 🔧 quick fix">
    **V3/V4:** ✓ / ✓

    Suggests removing the `Effect.gen` wrapper when the generator body contains only a single `return` statement. A single-expression generator adds indentation and `function*` syntax with no benefit.

    ```typescript theme={null}
    import { Effect } from "effect"

    // ❌ Before — unnecessary Effect.gen for a single expression
    const result = Effect.gen(function* () {
      return yield* Effect.succeed(42)
    })

    // ✅ After (quick fix applied) — direct expression
    const result = Effect.succeed(42)
    ```
  </Accordion>

  <Accordion title="unnecessaryFailYieldableError — 💡 suggestion + 🔧 quick fix">
    **V3/V4:** ✓ / ✓

    Suggests yielding yieldable error types (such as `Data.TaggedError` instances) directly with `yield*` instead of wrapping them in `Effect.fail`. Tagged errors implement the `Yieldable` interface, so they can be yielded directly for a more concise syntax.

    ```typescript theme={null}
    import { Effect, Data } from "effect"

    class NotFoundError extends Data.TaggedError("NotFoundError")<{}> {}

    // ❌ Before — wrapping a yieldable error in Effect.fail
    const program = Effect.gen(function* () {
      return yield* Effect.fail(new NotFoundError())
    })

    // ✅ After (quick fix applied) — yield* the error directly
    const program = Effect.gen(function* () {
      return yield* new NotFoundError()
    })
    ```
  </Accordion>

  <Accordion title="unnecessaryPipe — 💡 suggestion + 🔧 quick fix">
    **V3/V4:** ✓ / ✓

    Removes `pipe()` calls that contain no arguments. An empty `pipe()` call is a no-op and should be removed.

    ```typescript theme={null}
    import { pipe } from "effect"

    // ❌ Before — pipe with no arguments
    const result = pipe(someValue)

    // ✅ After (quick fix applied)
    const result = someValue
    ```
  </Accordion>

  <Accordion title="unnecessaryPipeChain — 💡 suggestion + 🔧 quick fix">
    **V3/V4:** ✓ / ✓

    Simplifies chained `pipe` calls into a single `pipe` call. When multiple `pipe(...)` calls are chained, they can always be flattened into one, improving readability.

    ```typescript theme={null}
    import { pipe, Effect } from "effect"

    // ❌ Before — chained pipe calls
    const result = pipe(
      pipe(
        someEffect,
        Effect.map((x) => x + 1)
      ),
      Effect.mapError((e) => new WrappedError({ cause: e }))
    )

    // ✅ After (quick fix applied) — single pipe call
    const result = pipe(
      someEffect,
      Effect.map((x) => x + 1),
      Effect.mapError((e) => new WrappedError({ cause: e }))
    )
    ```
  </Accordion>
</AccordionGroup>
