This is how I would go about it.
Right now, you don't have a type that represents the mapping between resource types and resources, so we'll need to define it.
type ResourceMapping = {
[ResourceType.A]: ResourceA
[ResourceType.B]: ResourceB
}
Then, you can use mapped types to specify the exact shape of your record.
type ResourceRecord = {
[R in ResourceType]: (r: ResourceMapping[R]) => void
}
Putting everything together, this is how it looks like
enum ResourceType {
A = 'a',
B = 'b',
}
export type ResourceA = {
type: ResourceType.A
name: "A"
}
export type ResourceB = {
type: ResourceType.B,
name: "B"
}
export type Resource = ResourceA | ResourceB
type ResourceMapping = {
[ResourceType.A]: ResourceA
[ResourceType.B]: ResourceB
}
type ResourceRecord = {
[R in ResourceType]: (r: ResourceMapping[R]) => void
}
const elements: ResourceRecord = {
a: (resource: ResourceA) => (
console.log(resource)
),
b: (resource: ResourceB) => (
console.log(resource)
)
}
Playground link
This way, adding a new enum entry without doing anything else will result in a compilation error, forcing you to make sure that you have an appropriate mapping between the new entry and a new resource (you can try it out in the playground).
Similarly, specifying the wrong value for a given resource type will fail at compilation time.
const wrongElements: ResourceRecord = {
// Type '(resource: ResourceB) => void' is not assignable to type '(r: ResourceA) => void'.
a: (resource: ResourceB) => (
console.log(resource)
),
b: (resource: ResourceB) => (
console.log(resource)
)
}