Why does my class method only auto-complete when the constructor is specified to return its own type?

Weird title but didn’t know how else to describe it.

Anyway, I’m working on rewriting and optimizing my OO wall cutter module which basically just creates parts around other parts, where these other parts are used as holes for windows.

So basically the module is laid out like this:

local module = {}
module.__index = module

-- class methods go here:
function module:GetActiveWallCutter()
    -- stuff
end

function module:GetWindowThatBelongsToPart()
    -- stuff
end

function module:GetOtherWindowsThatIntersectWindowXBounds()
    -- stuff
end

function module:AddWindowToWall()
    -- important:
    self = self :: WallCutter -- I type cast self as WallCutter
    -- stuff
end

-- now constructor:
function module.new(wall: Model)
    local newWallCutter = {}
    -- add properties
    return setmetatable(newWallCutter, module)
end

-- now here is where I'd put the types, so for example I define type WallCutter as module.new:
export type WallCutter = typeof(module.new(Instance.new('Model')))

return module

However, later in my :AddWindowToWall function, I try to call self:GetOtherWindowsThatIntersectWindowXBounds (long name sorry, bear with me)

-- it's called like so:
local otherWindowInfo = self:GetOtherWindowsThatIntersectWindowXBounds(window)

However it doesn’t auto-complete for some reason even though self is specified as type WallCutter in each method, including :GetOtherWindowsThatIntersectWindowXBounds:

function wallCutter:GetOtherWindowsThatIntersectWindowXBounds(window: Model)
	assert(window.PrimaryPart) -- doesn't error including at runtime
	self = self :: WallCutter -- no unknown type or anything

When I go to type it in, no auto-complete pops up:
image

However oddly enough, other functions do, only 2 though:
image

It’s only when I define the constructor like wallCutter.new(wall: Model): WallCutter that it shows all of the auto-complete functions:
image

Is there a reason this is happening, or is it just a bug or something?

Here’s the full constructor:

function wallCutter.new(wall: Model): WallCutter
	local newWallCutter = {}
	local part1 = wall:WaitForChild('Part1')
	local wallOrigin = (wall:WaitForChild('WallOrigin') :: CFrameValue).Value * CFrame.Angles(0,math.rad(90),0) :: CFrame
	newWallCutter.Origin = wallOrigin

	newWallCutter.LeftEdge = wallOrigin * CFrame.new(0, 0, -part1.Size.X / 2)
	newWallCutter.RightEdge = wallOrigin * CFrame.new(0, 0, part1.Size.X / 2)
	newWallCutter.TopEdge = wallOrigin * CFrame.new(0, part1.Size.Y / 2, 0)
	newWallCutter.BottomEdge = wallOrigin * CFrame.new(0, -part1.Size.Y / 2, 0)

	newWallCutter._wallCutoutResults = wall:WaitForChild('WallCutResults')

	newWallCutter.Wall = wall

	newWallCutter._windows = {} :: {
		[Model]: {
			Left: {BasePart};
			Right: {BasePart};
			Top: {BasePart};
			Bottom: {BasePart?};
		};
	};
	newWallCutter._windowFolder = wall:WaitForChild('Windows') :: Folder
	wallCutter._activeWallCutters[wall] = newWallCutter
	return setmetatable(newWallCutter, wallCutter)
end

export type WallCutter = typeof(wallCutter.new(Instance.new('Model')))

return wallCutter
1 Like

That isn’t how you infer a function type.

function wallCutter.new(wall: Model): (Model) -> WallCutter

‘self’ is just a reference to the object, this type cast only applies to that reference (not the object itself).

self = self :: WallCutter -- I type cast self as WallCutter
1 Like

It is, when you use a colon after the function’s arguments, that is what the expected return type is:

local function a(): () -> ()
	return 'b' -- not ok
end

local function b(): () -> ()
	return function() end -- ok
end

local function c(): 'b'
	return 'b' -- ok
end

image

() → () is just to define a variable’s type as a function:

--!strict

local a: () -> () = function(): string
	
end -- not ok, doesn't return type string

a = 'b' -- not ok

local a: () -> () = function(): string
	return 'c' -- ok
end

I’m a bit confused as to what you mean here. At the beginning of each function I type cast self as WallCutter which is just defined as typeof(wallCutter.new(Instance.new(‘Model’))) which is a table whose metatable is the module.

1 Like