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;

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

It’s got the __index referring to itself.

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


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:


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;

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

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


If I switch my ExplicitClassT definition:


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


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.

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.


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.


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.