Auto completes for function parameters when types are defined

With the following code and using the new type solver:

type Arg = "Hi" | "Player" | "Okay" | "Test"
type Task = typeof({
	buff = function(self: Task)

	end,
	start = function(self: Task)

	end,
	destroy = function(self: Task)

	end,
})
type Command = {
	name: string,
	aliases: {string}?,
	args: {Arg},
	prefixes: {string}?,
	autoPreview: boolean?,
	revokeRepeats: boolean?,
	cooldown: number?,
	run: (task: Task) -> ()
}


-- COMMANDS
local commands: {Command} = {
	
    --------------------
    {
		name = "dance",
		aliases = {"dce"},
		args = {"Player", "Okay"},
		prefixes = {"/", "@"},
		cooldown = 123,
		run = function(task)
			
		end,
	},


    --------------------
	{
		name = "fly",
		aliases = {"ccc2"},
		args = {"Player", "Test"},
	},

    --------------------
}


-- RETURN
return commands

Is it possible to have the parameter ‘task’ within function ‘run’ auto complete without defining the Task type for every command?

For example:

  1. Current setup, less desirable, but working:

    run = function(task: Task)
    	
    end,
    

  2. Desired setup, but not working:

    run = function(task)
    	
    end,
    

All the other auto competes work as expected (args, cooldown, name, etc).

It’s not necessary, but being able to do (2) would greatly help organise and reduce duplicate code. Curious is this is possible?

2 Likes

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.

2 Likes

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.

1 Like

Thanks for your response, opened up here:

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.