How do I minimise boilerplate code and hard dependencies when actor components need to interact with each other?

yeah im going through the same, i think the best way is to put the interface on the owner not the component that way if the component doesnt exist it can still return or fail. this also lets you override for example if i want to get health on my character i can call from a stats component but if i want to get health on a crate i can just return the variable directly.

otherwise you could initialize the component on the actor which passes through required dependencies. i like this option as you also know exactly when the component is loaded.

another way is to have components call events on the owner using dispatchers but this still requires more steps.

I am curious how others do it and i really wish interfaces could return delegates