Typed Luau Object Orientated Programming with New Type Solver

With the new type solver which includes globals like keyof, is there now a better way to do OOP compared to the following:

--!strict
-- LOCAL
local ExampleObject = {}
ExampleObject.__index = ExampleObject


-- CLASS
export type Class = typeof(setmetatable({} :: {
    firstName: string,
    lastName: string,
}, ExampleObject))


-- CONSTRUCTOR
function ExampleObject.new(): Class
	local self = {
		firstName = "firstName",
        lastName = "lastName",
	}
	setmetatable(self, ExampleObject)
	return self
end


-- METHODS
function ExampleObject.open(self: Class, useForce: boolean)
	
end


return ExampleObject

For example, is there a way define class properties only once instead of having to write them out twice (i.e. once under -- CLASS, and again under -- CONSTRUCTOR)?

1 Like
local Class = {}
Class.__index = Class

function Class:Method(): number
	return self.a + self.b
end

local function new()
	local self = {
		a = 10,
		b = 20
	}
	type Self = typeof(Class) & typeof(self)
	
	return setmetatable(self, Class) :: Self
end

return {new = new}

Works in the old type solver too

If you want something akin to a decorator, you can do something like this:

local function constructor<T, V, A...>(class: T, fn: (A...) -> V) -> (...: A...) -> T & V
	return function(...)
		local members = fn(...)
		return setmetatable(members, class)
	end
end

Then you can do this

--...

local new = constructor(Class, function()
	return {
		a = 10,
		b = 20,
	}
end

It’s a nice idea, but for my case won’t be as desirable because you lose type checking within the methods themselves, and the ability to use the Class type outside of the module

Code_2q8lkt3wM2

Idrk if this works but you can try this:

local Class = {}
Class.__index = Class

local function new()
	local self = {
		a = 10,
		b = 20
	}
	return setmetatable(self, Class)
end

export type Class = typeof(new())

function Class.Method(self: Class): number
	return self.a + self.b
end

return {new = new}

I dunno if this works but if it does thats pretty cool

1 Like

This works! Many thanks!

Here’s the final code for anyone in the future:

--!strict
-- LOCAL
local ExampleObject = {}
ExampleObject.__index = ExampleObject


-- CONSTRUCTOR
function ExampleObject.new()
	local self = {
		firstName = "firstName",
        lastName = "lastName",
        testPropery = "hi",
	}
    type Self = typeof(ExampleObject) & typeof(self)
	setmetatable(self, ExampleObject)
	return self
end


-- CLASS
export type Class = typeof(ExampleObject.new())


-- METHODS
function ExampleObject.open(self: Class, useForce: boolean)
	
end

function ExampleObject.close(self: Class, useForce: boolean)
	
end


return ExampleObject
2 Likes