Intellisense gets significatnly better with type notation. There is more than one way of going about it, though I find the approach MagmaBurnsV wrote about in their tidy article quite practical.
All mebers are properly displayed and self autocomplete in the constructor works too.
Example from the resource
local Car = {}
Car.__index = Car
type self = {
Speed: number
}
export type Car = typeof(setmetatable({} :: self, Car))
function Car.new(): Car
local self = setmetatable({} :: self, Car)
self.Speed = 100
self:Boost()
return self
end
function Car.Boost(self: Car): ()
self.Speed += 50
end
return Car
A bit different approach uses the type determined from Class.new().
Example
local Car = {}
Car.__index = Car
function Car.new(): CarType
local self = setmetatable({}, Car)
self.Speed = 100
self:Boost()
return self
end
function Car.Boost(self: CarType): ()
self.Speed += 50
end
export type CarType = typeof(Car.new())
return Car
The downside are exposed private members and the __index. Again, multiple solutions, mostly boiling down to preference. Write type checked code that suits you in terms of your development experience and productivity. Hiding private members normally means you ought to add some sort of an interface.
Among the resources I’m listing at least two that are worth a read.