Typed table with entry autocomplete

I would like to have a typed table, but I also like the autocomplete for the entries that Roblox Studio provides, since I know what’s in the table (if I type food., I can see all the entries in the food table).

The issue is that when I try to apply type checking to the table, the autocomplete stops working.
Example without types:

local food = {}

food.burger = {price = 100, category = "Main course"}

-- Autocomplete works, but a non-food object could be added to the table,
-- because the table doesn't have a specified type
-- Example:
food.cake = {pice = 100, category = "Dessert"}
-- Oops, the typo in "pice" could mess stuff up

Example with types (what I want):

type Food = {price: number, category: string}

local food: {[string]: Food}  = {}

food.burger = {price = 100, category = "Main course"}

-- If I type "food.", I don't see the "burger" entry
-- However, I can't accidentally add a non-food object into the table

Is there any way to get both?

Do you mean you want to create a food class?

It’s pretty simple, just make a module script with the following code:

local MyFoodClass = {}
MyFoodClass.__index = MyFoodClass

function MyFoodClass.new(_price,_category)
    local self = setmetatable({
        -- Object properties go here
        price = _price,
        category = _category
    }, MyFoodClass)
    return self
end

function MyFoodClass:changePrice(newPrice)
    self.price = newPrice
end

return MyFoodClass

(I ripped this off the AGF docs)

Then in the main script you can do:

local foodClass = require(SSS.FoodClass) -- Put the path of the module script here
local burger = foodClass.new(100,"Main Course")

print(burger.category) -- Main Course
print(burger.price) -- 100
burger:changePrice(120)
print(burger.price) -- 120

And as for the autocomplete, I have my timer object here using the class below, and you can see that Studio shows all of it’s properties in the script I created it in.


image

(ignore my terrible naming schemes)

1 Like

I want a table of things, not a class. Here’s a simpler example:

local foodPrices: {[string]: number} = {}

foodPrices.burger = 100

There’s no entry autocomplete, so I don’t know if there’s “burger” in the table, if the foodPrices table is in a different module script or something.

The autocomplete cannot evaulate your entire code at every point and determine the entries of every table you are working with. Therefore, unless you explicitly update the table in that line to have a ‘Burger’ value or create the table with a burger already in it, there is no way of knowing whether the table has a burger entry.

Additionally, this is not a safe practice for writing code. Relying on an autocomplete compiler can help you pick up spelling mistakes but you should write code to check for a burger entry before trying to use it.

From your original point, the best you can do is:

-- Create a food type, as you did
type FoodType = {
	price: number,
	category: string
}

-- Create a menu type but with an explicit index for "burger" and "cake". 
type MenuType = {
	burger: Food?,
	cake: Food?
}
-- Could optionally wrap ["burger"] and ["cake"] to make clear that they are strings

local menu: MenuType = {}

menu.burger = {{
		price = 100,
		category = "Main"
}}

--|                                |
--|                                |
--|      In later or other code    |
--|                                |
--|                                |

-- check to see if the burger exists in the table because it could be nil
if (menu.burger ~= nil) then
	-- do something with the burger, because you know it must be there.
end

This code above sets specific indexes for the menu but it will not tell you if the burger value is nil or has a table.

Hopefully this makes things a bit clearer.