How do I improve and add autocomplete to my OOP module?

I have this module:

local Classy = {}
Classy.__index = Classy

function Classy:extend()
	local Class = {}
	Class.__index = Class
	setmetatable(Class, {__index = self})
	return Class
end

return Classy

And another module script acting as a class:

local Classy = require(game:GetService("ReplicatedStorage").Classy)
local AnimalClass = Classy:extend()

function AnimalClass.new(Name:string)
	local Animal = setmetatable({}, AnimalClass)
	Animal.Name = Name
	return Animal
end

function AnimalClass:Speak()
	print(self.Name)
end


return AnimalClass

Then I have a server-side script, but it doesn’t have autocomplete for the AnimalClass functions.

local AnimalClass = require(game:GetService("ReplicatedStorage").AnimalClass)

local Dog = AnimalClass.new("Dog")

Dog:Speak()

The lack of autocomplete in your AnimalClass module occurs because your code editor (likely Roblox Studio or another Lua environment) cannot infer the structure of AnimalClass due to its dynamic nature. To resolve this and enable autocomplete, you can use type annotations and LuaDoc comments to define your class structure explicitly.

Here’s how you can improve your module to include autocomplete support:


Improved Code with Autocomplete

Classy Module

You don’t need to change much here since it’s a base module:

local Classy = {}
Classy.__index = Classy

function Classy:extend()
	local Class = {}
	Class.__index = Class
	setmetatable(Class, { __index = self })
	return Class
end

return Classy

AnimalClass Module

Add type annotations and LuaDoc comments to explicitly define the structure of AnimalClass:

local Classy = require(game:GetService("ReplicatedStorage").Classy)

-- Define the AnimalClass type
export type AnimalClass = {
	Name: string,
	new: (Name: string) -> AnimalClass,
	Speak: (self: AnimalClass) -> (),
}

local AnimalClass = Classy:extend()

-- Constructor
function AnimalClass.new(Name: string): AnimalClass
	local Animal = setmetatable({}, AnimalClass) :: AnimalClass
	Animal.Name = Name
	return Animal
end

-- Speak method
function AnimalClass:Speak()
	print(self.Name)
end

return AnimalClass

Server-Side Script

With the type annotations in place, your IDE (e.g., Roblox Studio with the Luau type checker) will now provide autocomplete:

local AnimalClass = require(game:GetService("ReplicatedStorage").AnimalClass)

-- Create a new instance of AnimalClass
local Dog = AnimalClass.new("Dog")

-- Autocomplete works for Dog:Speak()
Dog:Speak()

Key Improvements

  1. export type:

    • The export type keyword explicitly defines the AnimalClass type, listing all its properties and methods. This helps the IDE recognize the structure of your class.
  2. Type Annotations:

    • Adding Name: string and AnimalClass: AnimalClass makes the code self-documenting and aids in error checking.
  3. Explicit Casting:

    • The :: AnimalClass cast tells the type checker that Animal conforms to the AnimalClass type.
  4. Compatibility with Luau:

    • These changes leverage Roblox’s Luau type system, enabling autocomplete and catching type-related bugs during development.

Additional Tips

  • Documenting Methods:
    Add LuaDoc-style comments above each method for extra clarity:

    --- Makes the animal speak its name.
    function AnimalClass:Speak()
        print(self.Name)
    end
    
  • Custom Types:
    If you use more advanced class hierarchies, define shared types in a separate module for reusability.

  • IDE Support:
    Ensure you’re using an IDE that supports Luau type checking, like Roblox Studio or Visual Studio Code with the Rojo extension.

2 Likes

Thanks for the reply, however, this still doesn’t provide autocomplete :frowning:

what do you mean by “autoclomplete”

When I begin typing “Dog:” it doesn’t give any hints or autocomplete for its classes functions (Speak)

Not to strike a nerve, but…

Its VERY clear with the formatting, and the wording…

especially when you put a very detailed explanation with good formatting, punctuation, e.t.c.

And right after you put a poorly punctuated and short comment.

Don’t think AI will help you get solutions, most AIs aren’t smart enough to generate whole solutions for you.

Actually learn about the topic rather than asking AI, you will get a much more deep understanding of the topic. And you will be able to ACTUALLY help people.

5 Likes

Hey!

Can you put --!strict at the top of the editor of each script and let me know what warnings you get? You can view the warnings by hovering over the underlined text (if they show up). As already mentioned, the issue is with how the type solver infers your class type with inheritence.

2 Likes

This is a weird way to create classes, why are you extending?
Are you trying to do inheritence or something else?

Hey! So I just started to play around with the different orders of things, and added more specific type checking and got a version that actually works. Here are all the scripts (Just so you know I changed up the names a bit to make it easier to work with in studio):

Module 1:

local Classy = {}
Classy.__index = Classy

function Classy:extend()
    local Class = {}
    Class.__index = Class
    setmetatable(Class, {__index = self})
    return Class
end

return Classy

Module 2:

local Classy = require(game:GetService("ReplicatedStorage").Classy)

export type AnimalClass = {
    Name: string,
    new: (Name: string) -> AnimalClass,
    Speak: (self: AnimalClass) -> (),
}

local AnimalClass : AnimalClass = Classy:extend()

function AnimalClass.new(Name: string)
    local Animal = setmetatable({}, AnimalClass)
    Animal.Name = Name
    return Animal
end

function AnimalClass:Speak()
    print(self.Name)
end

return AnimalClass

The server script you can keep as normal and unchanged.

1 Like

In the animal class:
Cannot add property ‘new’ to table ‘{ @metatable {| __index: Classy |}, t1 } where t1 = {| __index: t1 |}’
Cannot add property ‘Speak’ to table ‘{ @metatable {| __index: Classy |}, t1 } where t1 = {| __index: t1 |}’
In the server script: Type ‘{ @metatable {| __index: Classy |}, t1 } where t1 = {| __index: t1 |}’ does not have key ‘new’‘’

@JAcoboiskaka1121’s method is working for me right now, but if you have a better method lmk

Thanks so much, works like a charm! :smiley:

But how do I add extra functions to the export type, and is it possible to “stack” them when I extend another class from one already with an export type?

copy and paste this line in the export type:

Speak: (self: AnimalClass) -> (),

for example, you could make a function to bark:

Bark: (self: AnimalClass) -> (),

then make a method, just like Speak, and there you go.

function AnimalClass:Bark()
	print(self.Name.." says woof!")
end

I’m not sure what you mean, a little more context will be helpful.

1 Like

edit: figured it out awdjawdawd

I’m assuming I have to wrap the entire module into another table and return that instead, but idk how :skull:

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.