Is it possible to enforce that when defining a generic class Foo<X>
, where X represents a discriminated union type, X must be a superset of another discriminated union Y?
In my specific scenario, I am utilizing a discriminated union to differentiate between various action types. In the context of an application using Redux, actions are distinct types with different payloads, and the Redux reducer is capable of accepting any action. Thus, I use a discriminated union of action types to describe the action parameter.
In the provided example, reminiscent of my actual issue, there is an extensible base class that can handle BaseActionTypes
. My goal is to pass in ExtendedTypes
as the generic parameter.
interface Run {
}
interface Walk {
}
type BaseActionTypes = Run | Walk
interface Jump {
}
type ExtendedActionTypes = BaseActionTypes | Jump;
class ActionDoer<ActionTypes extends BaseActionTypes> {
doAction(a: ActionTypes) {
}
walk() {
const w: Walk = {};
this.doAction(w); // ERROR!
}
}
class ExtendedActionDoer extends ActionDoer<ExtendedActionTypes> {
}
const extendedActionDoer = new ExtendedActionDoer();
const j: Jump = {};
extendedActionDoer.doAction(j);
The error generated by my code is:
Argument of type 'Walk' is not assignable to parameter of type 'ActionTypes'.
'Walk' is assignable to the constraint of type 'ActionTypes', but 'ActionTypes' could be instantiated with a different subtype
of constraint 'BaseActionTypes'.(2345)
I'm uncertain why the base ActionDoer
cannot execute doAction(w)
here. How can I ensure that whatever union of actions passed in as ActionTypes
includes at least the set of actions in the union
BaseActionTypes</code, potentially consisting of additional actions? Or, put differently, how can I specify that <code>ActionTypes
must be a superset of BaseActionTypes
for two discriminated union types X and Y?