effect icon indicating copy to clipboard operation
effect copied to clipboard

Layer.mock won't accept partials if unmocked methods/properties do not return Effect (also prevents use with Service)

Open dmeehan1968 opened this issue 1 month ago • 3 comments

What version of Effect is running?

3.19.7

What steps can reproduce the bug?

  class Test extends Context.Tag('Test')<
      Test,
      {
        foo: () => void,
        bar: () => void,
      }
  >() {
  }

  Layer.mock(Test, {
    foo: () => {},
  })
// ^ TS2345: Argument of type { foo: () => void; } is not assignable to parameter of type { foo: () => void; bar: () => void; }
// Property bar is missing in type { foo: () => void; } but required in type { foo: () => void; bar: () => void; }

What is the expected behavior?

Should work as shown above.

What do you see instead?

As above

Additional information

It works as expected if you mock all methods that don't return Effect.

This should also be the case for properties that are not effects (even though that's less likely to be required) but the Layer.mock example shows a property which is an Effect.

I was trying to create a Layer mock for @effect/platform's Path, which doesn't have a layerNoop helper. For example:

    const mockPath = Layer.mock(Path.Path, {
      resolve: (...args: string[]) => [...args].join(sep),
    } as Path.Path)

The cast is necessary to get around Layer.mock not accepting the partial as all methods in Path are plain functions.

### Effect.Service

This also means that Layer.mock doesn't work with Effect.Service unless the _tag is specified, along with any none effect properties. From the docs:

const MyServiceTest = Layer.mock(MyService, {
  _tag: "MyService",                       // comment this out to see error
  two: () => Effect.succeed(2)
})

dmeehan1968 avatar Nov 29 '25 11:11 dmeehan1968

This is the intended behaviour, as it only inspects the service at the type level.

The jsdocs could be updated if they don't mention this.

tim-smart avatar Dec 03 '25 00:12 tim-smart

Surely non-effect properties are still part of the type. Aside from Service, shouldn't this work with Context.Tag?

dmeehan1968 avatar Dec 03 '25 12:12 dmeehan1968

While they are part of the type, you can't cover off non-effect properties without introducing code generation.

tim-smart avatar Dec 03 '25 18:12 tim-smart