You can use the index type-function (new solver) that gets the value type based on the key type.
type AnimalMap = {
Cat: Cat,
Dog: Dog,
Bird: Bird,
}
-- pet: Cat
local pet: index<AnimalMap, "Cat">
The problem is the type for string arguments are inferred as string instead of a singleton, so they are incompatible.
function makeAnimal<Kind>(kind: Kind): index<AnimalMap, Kind>
-- also note this fails because record tables don't have indexers
return animalMap[kind]
end
-- Type Error: Property 'string' does not exist
-- what's happening is it's inferring kind: string
-- so it returns index<AnimalMap, string>, which is not what you want
local pet = makeAnimal("Cat")
-- casting to an explicit singleton fixes this
local pet2 = makeAnimal("Cat" :: "Cat")
The inference rules can’t change for backwards-compatibility reasons. Maybe when generic constraints arrive, they can take care of this edge case, but right now what you’re trying to do is impossible.