It seems that the inference is able to accurately know which type task is, even though autocomplete shows it as unknown.
This can be verified by doing this:
{
name = "dance",
aliases = {"dce"},
args = {"Player", "Okay"},
prefixes = {"/", "@"},
cooldown = 123,
run = function(task)
task.hello = "hi" -- Type '({ hello: string }) -> ()' could not be converted into '(Task) -> ()'; this is because it takes the 1st entry in the type pack is `{ hello: string }` in the former type and `Task` in the latter type, and `{ hello: string }` is not a supertype of `Task`
end,
},
Unfortunately, I believe this is a bug. Not sure if it has been reported yet.
In the meantime however, you can continue annotating the task argument with the Task type. And I would actually recommend doing this most of the time.
Can confirm, the type inference is working correctly under the hood (you’ll get proper type errors if you mess up), but LSP autocomplete just shows unknown.
If you want cleaner syntax you can also just use a type assertion:
run = function(task)
local typedTask = task :: Task
typedTask.buff(typedTask)
end,
Honestly, I’d stick with run = function(task: Task) as it’s more explicit and self-documenting anyway. Contextual typing from interface definitions is pretty standard in most typed languages, worth filing a bug report if no one else has yet.