Is it possible to map type literals for type annotation

Im making a module that kinda works like this

-- Define your types
type Cat = { meow: () -> () }
type Dog = { bark: () -> () }
type Bird = { fly: () -> () }

-- Map keys to types
type AnimalMap = {
	Cat: Cat,
	Dog: Dog,
	Bird: Bird,
}

function makeAnimal(kind)
	return {} :: AnimalMap[kind]
end

makeAnimal("Cat")
1 Like

using if statements the type checker realizes which type it should be
Probably not possible with a dictionary though

1 Like

yeah I tried using a dictionary and it didn’t work

-- Define your types
type Cat = { meow: () -> () }
type Dog = { bark: () -> () }
type Bird = { fly: () -> () }

-- Map keys to types
local animalMap : {
	Cat: Cat,
	Dog: Dog,
	Bird: Bird,
} = {};

function makeAnimal(kind)
	return animalMap[kind]
end

local a = "Cat";

print(animalMap[a]) -- doesn't work
print(animalMap["Cat"]) -- works?

makeAnimal("Cat")
1 Like

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.

1 Like

ok thanks
dg;dg;fkgdf;lgk;ldf;lgk

1 Like

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