Skip to main content
The Effect Language Service exposes refactor actions through your editor’s refactor menu (typically Ctrl+Shift+R / Cmd+Shift+R or right-click → Refactor…). Each refactor inspects the AST at the cursor, validates the surrounding context, and rewrites the code in place.
All refactors work in both Effect V3 and V4 unless noted otherwise.

Async/await conversions

These refactors operate on any async function declaration, function expression, or arrow function. Place your cursor anywhere inside the function and trigger the refactor menu.

asyncAwaitToFn

Converts an async/await function to Effect.fn, replacing await expr with yield* Effect.promise(() => expr) and wrapping the body in a generator. The function name is preserved as the trace string passed to Effect.fn. Support: V3 ✓ · V4 ✓

asyncAwaitToFnTryPromise

Like asyncAwaitToFn, but wraps each awaited expression in Effect.tryPromise and generates a typed error ADT (FetchError, etc.) for each catch site, giving you a typed error channel instead of UnknownException. Support: V3 ✓ · V4 ✓

asyncAwaitToGen

Converts an async/await function to Effect.gen, replacing await expr with yield* Effect.promise(() => expr). Unlike asyncAwaitToFn, the result is wrapped in Effect.gen rather than Effect.fn, so it is not a lazily-constructed pipeline. Support: V3 ✓ · V4 ✓

asyncAwaitToGenTryPromise

Like asyncAwaitToGen, but wraps each awaited expression in Effect.tryPromise with a generated typed error class. Support: V3 ✓ · V4 ✓

Generator refactors

effectGenToFn

Converts an Effect.gen(function*() { ... }) expression to Effect.fn("name")(function*() { ... }), promoting a one-shot generator into a reusable, traced pipeline function. Support: V3 ✓ · V4 ✓

wrapWithEffectGen

Wraps the expression under the cursor in an Effect.gen(function*() { return <expr> }) block, making it straightforward to add yield* statements around it. Support: V3 ✓ · V4 ✓

removeUnnecessaryEffectGen

Removes an Effect.gen wrapper when the generator body contains a single return statement with no yield* expressions, inlining the returned value directly. Support: V3 ✓ · V4 ✓

Function style

functionToArrow

Converts a function declaration to an equivalent const arrow function, preserving modifiers (e.g., export), type parameters, and parameters. Support: V3 ✓ · V4 ✓

toggleLazyConst

Toggles a const variable between a lazy thunk () => value and an eager value. Useful for deferring expensive computations or removing unnecessary laziness. Support: V3 ✓ · V4 ✓

togglePipeStyle

Toggles between the pipe(subject, f1, f2) free-function style and the subject.pipe(f1, f2) method-call style. The refactor detects which form is at the cursor and offers the opposite. Support: V3 ✓ · V4 ✓

toggleReturnTypeAnnotation

Adds or removes an explicit return type annotation on a function. When adding, it infers the type from the type checker and inserts it. Support: V3 ✓ · V4 ✓

toggleTypeAnnotation

Adds or removes an explicit type annotation on a const variable declaration. When adding, it infers the type from the type checker. Support: V3 ✓ · V4 ✓

pipeableToDatafirst

Converts pipeable-style calls (where the subject is passed as the last argument) to data-first style (where the subject is the first argument). Operates on the call expression at the cursor. Support: V3 ✓ · V4 ✓

wrapWithPipe

Wraps the current selection in a pipe(...) call. Select any expression, then apply this refactor to make it the first argument of a new pipe invocation. Support: V3 ✗ · V4 ✓

missedPipeableOpportunity (quick fix)

Triggered as a quick fix alongside the missedPipeableOpportunity diagnostic. Rewrites nested function calls into a single pipe call or .pipe chain, depending on your style preference. Support: V3 ✓ · V4 ✓

Layer composition

layerMagic

Automatically composes a set of layers into a correctly ordered pipeline of Layer.provide, Layer.merge, and Layer.provideMerge calls. This refactor has two phases:
1

Prepare

Place the cursor on a layer expression and apply Prepare layers for automatic composition. The refactor flattens all leaf layers into an array literal and wraps it with a cast: ([L1, L2, ...] as any) as Layer.Layer<TargetService>. The union of output types is computed and annotated on the cast.
2

Build

With the cursor on the prepared cast expression, apply Compose layers automatically with target output services. The refactor reads the dependency graph, determines the correct composition order, and rewrites the expression to L1.pipe(Layer.provideMerge(L2), Layer.provide(L3), ...). Any output types that could not be satisfied are listed in a trailing comment.
Support: V3 ✓ · V4 ✓
Use the Layer Graph hover (see Layer Graph) to visualise the dependency structure before running the build step.

Schema generation

makeSchemaOpaque

Converts a schema variable declaration into an opaque type pattern. Renames the original variable to Name_ and inserts exported opaque interface/type aliases for Name, NameEncoded, and NameContext (V3) or NameDecodingServices / NameEncodingServices (V4), plus a re-exported const Name with a full type annotation. Support: V3 ✓ · V4 ✓

makeSchemaOpaqueWithNs

Like makeSchemaOpaque, but additionally wraps the generated types inside a namespace matching the variable name, giving you UserId.Type, UserId.Encoded, etc. Support: V3 ✓ · V4 ✓

structuralTypeToSchema

Generates a recursive Effect.Schema from the structural shape of a type alias or interface, following all referenced types transitively. Unlike typeToEffectSchema, this uses the resolved type information from the checker rather than the syntactic form of the declaration. Support: V3 ✓ · V4 ✓

typeToEffectSchema

Generates an Effect.Schema declaration from a type alias or interface declaration. The cursor must be on the type name. Inserts the new schema constant immediately before the type declaration. Support: V3 ✓ · V4 ✓

typeToEffectSchemaClass

Generates a Schema.Class declaration from a type alias or interface. The class form gives you a nominal type with a class-based constructor, which is useful for tagged structs and error types. Support: V3 ✓ · V4 ✓

Service accessors

writeTagClassAccessors

Generates static override accessor methods on an Effect.Service or Effect.Tag class for service methods that have generic type parameters or multiple overloads. Each generated accessor delegates to the service method via Effect.andThen, providing a convenient static entry point with the full type signature. Support: V3 ✓ · V4 ✗ (not applicable in V4’s ServiceMap model)