A year later, I’ve managed to understand type generics and found a not-so-elegant-but-works-for-me solution:
local EnumsModule = {}
EnumsModule.newStringEnum = function<T>(enumTable: T)
local stringEnumTable = {}
for key,val in enumTable do
stringEnumTable[key] = key
end
table.freeze(stringEnumTable)
return stringEnumTable :: T
end
return EnumsModule

It requires me to type in the enum “table” values with empty strings (or any string as it’s just used for the type inference anyway), but the end result is where I only type it out once and autofill works. Ain’t that just nice?
EDIT (Feb 26, 2025):
Another year later…
The Plant reference project has a much safer way of doing this:

So you get all the benefits of strict mode like:

I ended up typing all the names this way anyway😅 It’s not really much trouble once you get used to it…