How to type-check metatable with __call method?

Related to other posts I currently found none to be able to solve my problem. I had been having an issue of type-checking metatable with metamethod and it was really annoying to solve. So I wonder if anyone has a solution to help me.

I want to be able to type-check and autofill metatable with metamethod and it’s variable, functions, value on studio only turn out Roblox LSP an extension that are used on VSCode has some issue that I won’t be taking in here.

The issue with normal setmetatable is that it autofill breaks down not usually with the __index method, but the __call when there is a function. I have an example code here

--!strict
local Meta = {}
Meta.__index = Meta

Meta.__newindex = function(self,Key,Value)
error(`Attempted to change or create {Key} with {Value}`)
end

Meta.__call = function(self,Text)
print(Text)
end

function Meta:Foo()
print("Foo")
end

local Table = {}
Table.String = "Hello World!"

setmetatable(Table,Meta)

Table. -- Autofill

Now when doing that the autofill will show a bunch of stuff that we don’t want to show. It may not matter to other people but It might matter for people that are sharing a project and working together with a framework or a module that doesn’t have proper documentation to tell which is which and how it operates.
image
The unnecessary values like __index, __newindex, __call are shown.
When attempting to call the __call function the parameter doesn’t show and yet leads to confusion and makes you must go back to the module or the script you are working on to check what you should put there.
image

Now because of all of these I came up with a kind of working solution by manipulating the type-checking and assigning the new metatable as a custom type. The code I had came up:

--!strict
local Meta = {}

function Meta:Foo()
	print("Foo")
end

local Table = {}
Table.String = "Hello World!"

local function Assign()
	return setmetatable(Table, {
		__index = Meta,

		__newindex = function(self, Key, Value)
			error(`Attempted to change or create {Key} with {Value}`)
		end,

		__call = function(self, Text: string)
			print(Text)
		end,
	}) :: typeof(Table) & typeof(Meta) & (Text: string) -> nil
end

local MetaTable = Assign()

MetaTable(MetaTable.String)

Although work. But the luau type-check won’t accept because of Cannot call non-function Table

So I wonder if there anyways I can make luau type-check accept it as an actual type and function like it should in –!strict mode

It just randomly worked. I was just wondering if I can try union and then it returns an error so I try wrapping it in parentheses and it gives a warning and then I return to the Intersection and it… it just works.

--!strict
local Meta = {}

function Meta:Foo()
print("Foo")
end

local Table = {}
Table.String = "Hello World!"

local function Assign()
return setmetatable(Table, {
__index = Meta,

__newindex = function(self, Key, Value)
error(`Attempted to change or create {Key} with {Value}`)
end,

__call = function(self, Text: string)
print(Text)
end,
}) :: (typeof(Table) & typeof(Meta)) & (Text: string) -> nil
--Added parentheses between (typeof(Table) & typeof(Meta)) although should work the same without parentheses.
end

local MetaTable = Assign()

MetaTable(MetaTable.String)

I am horrify of how luau type-check work.

2 Likes

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