ExtendedInstance - Class + Instance in one variable

Tired of needing to use instance and it’s info with 2 variables every time? Have classes that revolve around some instance? ExtendedInstance will make that much easier.

The function (you add this into module):

local currentKey : string = nil

local function callInstanceMethod(t, ...)
	return t.__extendedInstance[currentKey](t.__extendedInstance, ...)
end

local function returnInstanceValue(instance, index)
	return instance[index]
end

return function(t, k)
	local class = getmetatable(t)
	local classValue = class[k]

	if classValue then return classValue end

	local extendedInstance = rawget(t, '__extendedInstance')

	if not extendedInstance then return end

	local success, value = pcall(returnInstanceValue, extendedInstance, k)

	if not success then return nil end

	if type(value) == 'function' then
		currentKey = k
		return callInstanceMethod
	end

	return t.__extendedInstance[k]
end

How to extend instance with your class?

Just add ExtendedInstance function as .__index when creating your class and add .__extendedInstance to self

local Class = {}
Class.__index = ExtendedInstance -- the function from above

function Class.new(instance)
    local self = {}
    setmetatable(self, Class)
    
    self.__extendedInstance = instance
    self.Number = 5

    return self
end

function Class:Foo()
    print('bar')
end

When inheriting from class that extends from instance, this class should have extendedInstance function as it’s .__index too to work.

local ClassThatInherits = {}
ClassThatInherits.__index = ExtendedInstance
setmetatable(ClassThatInherits, Class)

function ClassThatInherits.new(instance)
    local self = Class.new(instance)

    return self
end

Now you can use methods and properties of both instance and class with just one variable (getting instance children works too).

local part = workspace.Part
local extendedPart = Class.new(part)

print(extendedPart:GetFullName()) -- will print "Workspace.Part"
print(extendedPart.Number) -- will print "5"
print(extendedPart.Name) -- will print "Part"
extendedPart:Foo() -- will print "bar"

Caution! When using roblox methods that require instance as argument get it by .__extendedInstance for example:

local Players = game:GetService('Players')
local extendedPlayer = Class.new(player)
local character = Players:GetPlayerFromCharacter(extendedPlayer.__extendedInstance)