Metamethod __type

So, I was reviewing the documentation, and I was looking to make my own library and create my own classes. However I ran into one issue:

local meta = {__type = "Custom Type!"};
local obj = setmetatable({}, meta);
print(type(obj));

Using type() on my class just returns table. I even tried implementing it the same way shown in the documentation.

local obj = {__type = "Custom Type!"};
local meta = {__index = obj};
print(type(setmetatable({}, meta)));

A friend of mine said that roblox doesn’t allow custom types. Why would they provide it in the documentation if we aren’t allowed to use it? Like a father buying 2 fishing poles and going fishing without his neglected son.

1 Like

If you check the code carefuly you will notice that they don’t get the datatype with type function, they check it manually:

And they never mention about the __type metamethod in the list of metamethods. So I don’t know what are oyu trying to prove here:

so how do I make it return my custom type with type or typeof? I’d like to also include roblox types and native types

They probably use another method that doesn’t involve metamethods because otherwise it would be a bit problematic for many reasons.

Or if they do, they don’t read the ones from metatables that can be changed by user.

You’ll have to wrap around it yourself.

local old_typeof = typeof

local function typeof(arg: any): string
    local mt = getmetatable(arg)

    if mt and mt.__type then
        return mt.__type
    end
    return old_typeof(arg)
end
5 Likes

Closest you can do to get that would be through type script:

type myType = {[string]: any}

local _type: myType = {
    Index = 1
}

print(type(_type)) --> table

But still wouldn’t be a custom datatype.

or do what @sjr04 did

Why does it have to get the metatable of arg? Does this work if I pass anything besides a metatable?

So that it can get the __type “metamethod”

I thought this would be useful

Using @sjr04’s method
If you want to use custom typing, while protecting the majority of the metatable, you can do this:

local meta = {
	__metatable = {
		__type = 'fish'
	},
	__newindex = function(self, i, v)
		print(i, v)
		rawset(self, i, v)
	end,
	__index = function(self, i)
		print(i)
		return rawget(self, i)
	end
}

This way, whenever you get the metatable, it will return __metatable, and everything else will be protected; __newindex and __index cannot be accessed from the getmetatable global.

local obj = setmetatable({}, meta)

print(getmetatable(obj).__type) --"fish"

The typeof function that @sjr04 provided will work exactly the same as before.


You can protect __metatable as well, but it is somewhat hacky and I would only recommend it for objects that are frequently and publicly used:

local meta = {}
do
	local __metatable = {
		__type = 'fish'
	}

	local proxy = newproxy(true)
	local proxy_meta = getmetatable(proxy);
	proxy_meta.__index = function(self, i) return __metatable[i] end
	proxy_meta.__metatable = 'locked'

	meta.__metatable = proxy
end
1 Like