My approach is to declare the signals at a global level.
Then any node can connect to a signal as a listener, and any node can emit a signal. The emitting node and the listening node don't have to know about each other. They only have to know the name of the autoload, the name of the signal and the signal parameter types (if any).
Example (Godot 4):
# signal declaration, in a script that's attached to an autoload named Events
extends Node
@warning_ignore("unused_signal")
signal show_credits(visible: bool)
# in the signal listener node
Events.show_credits.connect(_on_show_credits)
...
func _on_show_credits(visible: bool) -> void:
...
}
# in the signal emitter node
Events.show_credits.emit(true)
(Warning: xyz may whine about this, because he hates autoloads.)