As a developer, when I use RBXScriptSignal I have no control over its type. This is especially problematic when I’m working with custom events from BindableEvents or RemoteEvents. Consumers of these events have to just know what they return. It would be great if these were templates that let me just input what I want as the parameters.
No, they don’t.
Bindables are sort of a discouraged API to use, because in cases like these it is impossible for them to have their type inferred.
Instead, you should use a callback system, which not only guarantees strong typing but also avoids creating two separate callbacks that may cause race conditions.
-- Module
local PlayerData = {
OnDataLoaded = nil :: (Player: Player) -> ()?
}
local function LoadData()
local Callback = PlayerData.OnDataLoaded
if Callback then
for Index, Player in Players:GetPlayers() do
Callback(Player)
end
end
end
-- Consumer
local function OnDataLoaded(Player: Player)
end
PlayerData.OnDataLoaded = OnDataLoaded -- Properly Checked
As for Remotes, the types they may return are completely deterministic. You should always type every argument as unknown
and do some runtime checking (unless its Server → Client, where you can guarantee the types)
?
I was able to use it fine a while back:
Just ignore my previous replies
Heads up, they’re kind of working against typing for network callbacks (RemoteEvent
s and RemoteFunction
s) with the unknown
type:
, i.e., unknown
has to be narrowed down and is specifically intended for data sent “over the wire”, and it appears to have been enabled with the new type solver (albeit with a bug where the guaranteed parameter is incorrectly unknown
and not Player
):
I’ve forked stravant’s GoodSignal implementation to support types. There’s a pretty wide range of benefits for using pure-Lua signals rather than RBXScriptSignals, so if you plan to switch to that, you could use this:
GoodSignalFork.lua (7.7 KB)
Example usage:
local GoodSignal = require(path.to.GoodSignal)
-- create the signal, and the public signal with no :Fire method
local privateSignal = GoodSignal.new()
local publicSignal = privateSignal:GetEventOnlySignal() :: GoodSignal.Signal<number, string>
-- connect to the public signal
publicSignal:Connect(function(a, b) -- intellisense: a is a number, b is a string
print(a, b)
end)
-- fire the signal from both the private and public objects
privateSignal:Fire(2, "wow")
publicSignal._Signal:Fire(3, "This also works")