Type-Checking Metatables

Heyy! :V

Tiny Note: I’ll be editing this post as I come across new methods, some replies may seem out of date :3
It’s recommended you know the basics of type-checking, here’s an awesome post to check out!

This tutorial covers two methods (so far) and it’s useful to know both!

✧・:ָ₊・ 1. Seperate Type-Checks 𓂃ָ-࣪☁

This approach type-checks the basetable and metatable seperately, then combines them using setmetatable() while preserving each table’s type.

-- Method 1. Seperate Type-Checks

-- Create  basetable and  metatable,  specifing a  custom 
-- table  type  for  each.   We  are  using  assertation,
-- which allows us to set the type during declaration. 
local Basetable = {
	foo = "x_o"
} :: {
	foo : string
}

local Metatable = {
	__index = {
		bar = true
	}
} :: {
	__index : {
		bar : boolean
	}
}

-- Combine our tables, this will preserve our type-checking!
local Composite = setmetatable(Basetable, Metatable)

This method allows the basetable and metatable to retain their custom types, even if we later split them apart. This method becomes problematic when the composite table is the return parameter; as type-checking a return result requires a combination basetable-metatable type.

.

✧・:ָ₊・ 2. Combined Custom Type 𓂃ָ-࣪☁

This approach combines the basetable and metatable types into one single custom type. This custom type can be used to type-check the return result of functions or modules. See documentation on this approach here (recommended) :3

--  Method 2. Combined Custom Type

-- Define a single custom type  containing our basetable 
-- and metatable structures. We are using the same table
-- structure as the last approach.
type Composite = typeof(setmetatable(
	{} :: { -- Basetable structure.
		foo : string
	}, 
	{} :: { -- Metatable structure.
		__index : {
			bar : boolean
		}
	}))

-- Create our table using the defined layout of our type.
local Composite : Composite = setmetatable(
	{ -- Basetable
		foo = "xwo"
	}, 
	{ -- Metatable.
		__index = {
			bar = true
		}
	})

.

It’s pretty simple, but lots of the documentation is buried -w\ Hopefully this will assist developers by providing an easier to find reference :3

Good luck on your procrastinative perfectionist coding!! ^w^

3 Likes

Or you can do this, if you wanna save some time:

type Basetable = typeof(setmetatable({} :: {foo: boolean, bar: {string}}, {}))
local newTable: Basetable = setmetatable({foo = true, bar = {"OwO"}}, {})
2 Likes