Right now, organizing custom object types in modules and providing a form of type enforcement between arbitrary modules is difficult, even in strongly typed Luau. I need the ability to constrain input object types across two or more arbitrary modules that are not necessarily designed in a manner that requires them to be together without having to explicitly define the type in both modules, and most importantly, in a manner where both modules are not necessarily required to have strict types enabled.
To resolve this problem, I think typeof
should recognize user-defined Luau types, and return the user-defined name, albeit with an added prefix to prevent spoofing Roblox types (e.g. luaobj:
as a prefix)
Take this for example:
--!strict
local MyModule = {}
export type TheTypeEtiMade = {
Greeting: string
}
function MyModule.new(): TheTypeEtiMade
return { Greeting = "Hello, Gordon!" }
end
return MyModule
If I use this in another script:
--!strict
local MyModule = require(path.to.MyModule)
local obj = MyModule.new()
print(typeof(obj))
-- ^ Expected output: TheTypeEtiMade
In general, the ability to define custom type names would be a good addition for publicly shipped APIs as it provides a more standardized method of identifying pseudo-objects created in pure Lua.
My solution right now is a sandboxed variant of typeof
that looks at objects’ metatables for a __type
index which should be set to a string. If this new variant of typeof
receives a table with a metatable which has defined __type
string, it will return that string instead of "table"
, and I would like to be able to drop this method in favor of the aforementioned feature. It is not a very clean solution and absolutely not optimal in terms of extreme performance benchmarks.
The code can be seen here:
--!strict
local oldtypeof = typeof
local function typeof(objIn: any): string
local objType = oldtypeof(objIn)
if objType ~= "table" then return objType end
-- Could be a custom type if it's a table.
local meta = getmetatable(objIn)
if oldtypeof(meta) ~= "table" then return objType end
-- Has a metatable that's an exposed table.
local customType: string? = meta["__type"] -- I want to mandate that this is a string.
if customType == nil then return objType end
-- Has a type field. Ignore beta type checker warning of string | nil here.
return customType
end
return typeof