Intellisense not picking up 'self' on OOP functions

I was recently brain-storming with a friend of mine trying to wrap our heads around why only some class functions were able to utilize “self” in an attempt to make writing a class easy and without explicit definition.
It’s 100% possible AS LONG AS the functions underneath the class were explicitly used (not in a loop of some kind, has to be typed out like self:Function() )
Video :


Place File : Place1.rbxl (55.1 KB)

Expected behavior

I expected the class to automatically pick up intelli-sense from within the functions just via metatables without having to explicitly run a function in its constructor method.

The reason this doesn’t work is because nothing about the code actually requires that the type of self in Explode be the same type as the type of the self variable in your constructor without the call to it. That’s why you see a plain free type a for self, it’s entirely unconstrained.

This is definitely the worst kind of “technically correct” since we understand that humans write colon definitions expecting the self types to all be consistent, but as-is this is more of a feature request for a change to type inference than a bug.

This restriction on type inference is nevertheless already a planned addition to the Luau language, described here as “shared self types”. It will be implemented as part of the New Type Solver after it is released generally (i.e. when it is out of beta).

2 Likes

The work around I found for this is to reflect self as a type from the constructor.

local BUILDING = {}
BUILDING.__index = BUILDING

-- Constructs a new building.
function BUILDING.new(BuildingObject : Model)
	local self = setmetatable({}, BUILDING)
	self.Parts_Destroyed = 0
	return self
end

-- Causes the building to explode.
function BUILDING:Explode()
	local self : typeof(BUILDING.new()) = self
	self.Parts_Destroyed += 20
	
end

return BUILDING 

I’d do this instead

local BUILDING = {}
BUILDING.__index = BUILDING

-- Constructs a new building.
function BUILDING.new(BuildingObject : Model)
	return setmetatable({
        Parts_Destroyed = 0
    }, BUILDING)
end

export type Building = typeof(BUILDING.new())

-- Causes the building to explode.
function BUILDING.Explode(self: Building)
	self.Parts_Destroyed += 20
end

return BUILDING 

It’s pretty tedious writing local self: type = self and it’s redeclaring a variable when you don’t need to

Also this way you can use the type outside the methods

1 Like