Home > database >  Rails AggregateRoot "on" handlers not detected as instance methods
Rails AggregateRoot "on" handlers not detected as instance methods

Time:07-12

In Rails event store, AggregateRoot has DSL methods that result in blocks with this shape:

class X
  extend AggregateRoot::OnDSL

  class MyEvent < RailsEventStore::Event; end

  on MyEvent do |event|
    # Code
  end
end

Inside that block, there's access to the class instance data. But sorbet don't know about it.

Is there a way to tell Sorbet that that block will be injected as an instance method?

I can mark every use of fields or methods as T.unsafe(), but that would remove the typing from it, and adding a cast makes the code harder to read

CodePudding user response:

You can use T.bind to communicate to Sorbet that self has a particular type in a particular block:

class X
  extend AggregateRoot::OnDSL

  class MyEvent < RailsEventStore::Event; end

  on MyEvent do |event|
    T.bind(self, MyEvent)
    # Code
  end
end

More generally, you can add a shim which specifies the type of a DSL API like this, and specify the type the proc will be bound to, like: T.proc.bind(TheTypeOfSelfInTheBlock).params(...).returns(...).

In this case, it's a bit tricky for AggregateRoot::OnDSL.on, if not impossible, for two reasons:

  1. on takes a *event_klasses. You can't be sure which event class triggered your block, so you don't statically know which of the event_klasses the event passed to your block will be.
  2. The type of event_klasses should be event_klasses: T.class_of(RailsEventStore::Event). Even if it were one singular value, you would need the generics system to let you express that the block's argument is specifically the type of event_klasses (and not just any RailsEventStore::Event). I don't think that's currently possible.
  • Related