Please suggest a better title, I am not sure what exactly to ask.
I have a type definition that looks like this:
type Animal =
| {
'species': 'cat'
'action': 'meow'
}
| {
'species': 'cat'
'action': 'whine'
}
| {
'species': 'dog' | 'tree'
'action': 'bark'
};
I want to define a conditional type ActionsFor<S> that results in a narrowed-down type of the given species. For example:
type CatActions = ActionsFor<'cat'> // should be 'meow' | 'whine'
type DogActions = ActionsFor<'dog'> // should be 'bark'
type TreeActions = ActionsFor<'tree'> // should be 'bark'
type BarkActions = ActionsFor<'dog'|'tree'> // should be 'bark'
My current attempt is close but does not work as I want with the unioned species:
type ActionFor<S extends Animal['species']> = Extract<Animal, {species: S}>['action']
Which results in:
type CatActions = ActionsFor<'cat'> // correct - 'meow' | 'whine'
type DogActions = ActionsFor<'dog'> // WRONG - never
type TreeActions = ActionsFor<'tree'> // WRONG - never
type BarkActions = ActionsFor<'dog'|'tree'> // correct - 'bark'
How can I redefine ActionsFor to do what I want?