Explicit Class Type with Methods

Hey guys, I’m trying to wrangle the type checker so it provides good intellisense for my classes. For reasons, I can’t just cut over all my classes so they use the Roblox Approved™ method of classes, but I do want to get intellisense that behaves similarly to it.

So, this is what I consider to be a Roblox Approved™ class:

local TestClass = {};
TestClass.__index = TestClass;

function TestClass:SetName(name: string)
	self._Name = name;
end

function TestClass.new()
	local self = setmetatable({}, TestClass);
	self._Name = "Unnamed";
	return self;
end

It’s got the __index referring to itself.

When you instantiate one of these objects & start typing a colon, you get suggestions:

img2

The type checker “knows” that the first argument is “self” and doesn’t suggest that the first argument should be our class type.

Moreover, if you use a period, it lets you know what you’re doing wrong:

img5

However, if I try to define my type explicitly, such as with this code:

type ExplicitClassT = {
	SetName: (self: ExplicitClassT, name: string) -> ();
	_Name: string;
}

local ExplicitClass = {};
ExplicitClass.Meta = {__index = {}}

function ExplicitClass.Meta.__index:SetName(name: string)
	self._Name = name;
end

function ExplicitClass.new(): ExplicitClassT
	local self = setmetatable({}, ExplicitClass.Meta);
	self._Name = "Unnamed";
	return self;
end

My intellisense instead thinks that I should be putting two arguments in for the SetName function.

img4

If I switch my ExplicitClassT definition:

image

This will work for the colon construction, but not the period construction.

image
image

So, in summary, what can I do to achieve the proper intellisense behavior that Roblox Approved classes get? In short, I want the “self” variable to show up in intellisense when you use a period, but NOT when you use a colon to reference the method.

I’ve already scoured Type checking - Luau for an answer, but it doesn’t really talk at all about what a class would look like.

1 Like

Apparently declaring the method as a type generic, silences the “self: Explicit” in docs

What did you write on line 16?

I’m trying to shuffle your ideas into my ExplicitClassT example up above, but I can’t even see where a setmetatable happens.

Anyway, if I try to change my definition of the SetName type to use generics, I don’t get any closer. The first attempt is somewhat silly; just uses a generic type & doesn’t do anything with it.

My second approach actually uses the generic as the first argument to the method. This feels more right because there is an argument there.

img7

But the intellisense still doesn’t understand that colon. Static analyzer is at least right in this scenario.

Unfortunately, none of this gets me any closer than not using generics.

image


it turns out Roblox’s own docs have the (self, …) effect happening lol, I think what you did is intended behaviour because Luau supports . and : interchangably

There must be something under the hood that can work around this because idiomatic classes work around this (see my first post with the “TestClass” that handles periods/colons properly).

I don’t know if there’s any exposed way to do this with an explicit class type, though.