-
I'm creating definition files for the Elder Scrolls Online API. It defines global values for event IDs and a registration function. What's possible and what are best practices for annotating a callback system? I've got a sort of minimal working example below, which includes two specific questions: -- The API defines global event IDs
EVENT_A = 1
EVENT_B = 2
-- I tried to create an enum of events like this:
---@alias EventId
---| `EVENT_A`
---| `EVENT_B`
-- I annotated the callback registration like so:
---@param eventId EventId
---@param callback function
function RegisterForEvent(eventId, callback) end
-- The event A callback only passes the event id.
RegisterForEvent(
EVENT_A,
function(eventId) print("event A happened with eventId", eventId) end
)
-- The event B callback also passes a number
RegisterForEvent(
EVENT_B,
function(eventId, bNumber)
print(string.format("B with eventId %d and number %f", eventId, bNumber))
end
)
-- Question 1: Can type-checking identify that 3 is not a valid eventId? It's not
-- flagging this one.
RegisterForEvent(3, function() end)
-- Question 2: Is there a way that type-checking can identify that the callback has
-- the wrong signature?
RegisterForEvent(EVENT_A, function(a, b, c) end) |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 3 replies
-
It seems like I made up a capability in the example above that doesn't work. This doesn't work:
The
|
Beta Was this translation helpful? Give feedback.
-
Maybe this is related to #2721 |
Beta Was this translation helpful? Give feedback.
-
---@alias EventId
---| 1
---| 2 the type checking of eventId starts to work.
Just using your example above, you can have something like this: EVENT_A = 1
EVENT_B = 2
---@alias EventId
---| 1
---| 2
---@param eventId EventId
---@param callback function
---@overload fun(eventId: 1, callback: fun(eventId))
---@overload fun(eventId: 2, callback: fun(eventId, bNumber: number))
function RegisterForEvent(eventId, callback) end
-- both `RegisterForEvent` calls in your 2 questions will throw error now
-- first one with `param-type-mismatch` warning
-- the other one with `redundant-parameter` warning But as you can see, the above annotation is not that great because of the direct writing of the enum values, instead of writing enum names. Now I can come up with the following improvement: to alias each enum value with its name EVENT_A = 1 ---@alias EventId.EVENT_A 1
EVENT_B = 2 ---@alias EventId.EVENT_B 2
---@alias EventId
---| EventId.EVENT_A
---| EventId.EVENT_B
---@param eventId EventId
---@param callback function
---@overload fun(eventId: EventId.EVENT_A, callback: fun(eventId))
---@overload fun(eventId: EventId.EVENT_B, callback: fun(eventId, bNumber: number))
function RegisterForEvent(eventId, callback) end Although for each new enum, you have to write it 3 times:
But hey, now you can use the type names when writing function overload definitions 🎉 |
Beta Was this translation helpful? Give feedback.
3
is not a valid eventId, you have to specify the accepted param type ofeventId
to be a union of1
and2
only.As you have experimented, the
backtick
literal type is only for auto completion hint, if you have an alias which are all thesebacktick
literal, the alias type is stillany
, and that's why when changed to the following:the type checking of eventId starts to work.
@overload
annotation, and you can overload a function signature based on the param value. LuaLS will try to type narrow it to the correct signature, but as far as I know this functionality is not that perfect. Still we can give a try.