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:
on
takes a*event_klasses
. You can't be sure which event class triggered your block, so you don't statically know which of theevent_klasses
the event passed to your block will be.- The type of
event_klasses
should beevent_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 ofevent_klasses
(and not just anyRailsEventStore::Event
). I don't think that's currently possible.