如何为可区分联合的超集创建通用约束
How do I make a generic constraint for a superset of a discriminated union
在定义泛型class Foo<X>
时,其中X旨在成为可区分的联合类型,有没有办法表达"X must be a superset of the discriminated union Y"?
我有一种情况,我正在使用可区分的联合来表示不同的动作类型。这个真实世界的上下文是一个使用 Redux 的应用程序,所以每个动作都是不同的类型,具有不同的负载,而 Redux reducer 是一个可以接受任何动作的函数,所以我使用动作类型的可区分联合来描述动作参数。
在下面的示例中,它类似于我的真实问题,我有一个可扩展的基础 class,它知道如何处理 BaseActionTypes
,我希望能够传入 ExtendedTypes
作为通用参数
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);
我的代码生成错误:
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)
我不太清楚为什么基础 ActionDoer
不能 doAction(w)
在这里。我正在尝试添加一个约束,表示“无论作为 ActionTypes
传入的任何动作联合,它都必须至少包括联合 BaseActionTypes
中的一组动作,并且可能包括其他动作。或者,换句话说,ActionTypes
必须是 BaseActionTypes
的超集
我认为 ActionTypes extends BaseActionTypes
可能不是我想做的事情的正确约束类型?最初 extends
似乎是正确的,因为 ExtendedActionTypes
是 BaseActionTypes
的 "extension",但是从 class 继承的角度考虑这一点让我意识到 extends
可能不是这样做的正确方法。 (即,如果 class A 扩展 class B,则 A 拥有 B 中的所有字段,再加上更多。而 ExtendedActionTypes
和 BaseActionTypes
之间的关系不正确。
是否有更好的方法来表达对可区分联合的约束,例如对两个可区分联合类型 X 和 Y 说 "X must by a superset of Y"?
通用类型在这里如何与 extend
一起工作是我们限制我们的 class 最终将包含来自 BaseActionTypes
的一个或多个可能的成员。对于 union types extends 意味着 - 所有可分配给该类型的东西,这意味着它可以具有相同数量或更少的变体,但仅此而已。你问你的类型 ExtendedActionTypes
如果它有一个选项 more .. 真的不是,那只是因为你没有填写类型的实现,这三个都和 TS 一样是结构类型语言。如果你添加到这些类型和属性你将有一个错误,check this here.
所以 ExtendedActionTypes
不能分配给 BaseActionTypes
因为它有更多的选择。
你的错误虽然有不同的原因,因为你试图将类型 Walk
的值设置为 ActionTypes extends BaseActionTypes
的值。这意味着 ActionTypes
是不包含 Walk
的可能类型,因此您无法执行此类赋值。证明下方:
// no error as `Run` extends `BaseActionTypes`
class ExtendedActionDoer extends ActionDoer<Run> {
}
如您所见,Walk
无法分配给 Run
。
可能的问题修复之一是从 class 中完全删除约束:
type ExtendedActionTypes = BaseActionTypes | Jump;
class ActionDoer {
doAction<ActionType extends BaseActionTypes>(a: ActionType) {
}
walk() {
const w: Walk = {type: 'Walk'};
this.doAction(w);
}
}
class ExtendedActionDoer extends ActionDoer {
doAction(a: ExtendedActionTypes) {
}
}
const extendedActionDoer = new ExtendedActionDoer();
const j: Jump = {type: 'Jump'};
extendedActionDoer.doAction(j);
我们也可以保留通用但需要属性,考虑:
type ExtendedActionTypes = Jump;
class ActionDoer<ActionType> {
doAction(a: ActionType | BaseActionTypes) {
}
walk() {
const w: Walk = {type: 'Walk'};
this.doAction(w);
}
}
class ExtendedActionDoer extends ActionDoer<ExtendedActionTypes> {
doAction(a: ExtendedActionTypes) {
}
}
const extendedActionDoer = new ExtendedActionDoer();
const j: Jump = {type: 'Jump'};
extendedActionDoer.doAction(j);
最重要的部分是 - doAction(a: ActionType | BaseActionTypes)
我是说无论你给我什么,我都会接受,但总会有 BaseActionTypes
的成员。
在定义泛型class Foo<X>
时,其中X旨在成为可区分的联合类型,有没有办法表达"X must be a superset of the discriminated union Y"?
我有一种情况,我正在使用可区分的联合来表示不同的动作类型。这个真实世界的上下文是一个使用 Redux 的应用程序,所以每个动作都是不同的类型,具有不同的负载,而 Redux reducer 是一个可以接受任何动作的函数,所以我使用动作类型的可区分联合来描述动作参数。
在下面的示例中,它类似于我的真实问题,我有一个可扩展的基础 class,它知道如何处理 BaseActionTypes
,我希望能够传入 ExtendedTypes
作为通用参数
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);
我的代码生成错误:
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)
我不太清楚为什么基础 ActionDoer
不能 doAction(w)
在这里。我正在尝试添加一个约束,表示“无论作为 ActionTypes
传入的任何动作联合,它都必须至少包括联合 BaseActionTypes
中的一组动作,并且可能包括其他动作。或者,换句话说,ActionTypes
必须是 BaseActionTypes
我认为 ActionTypes extends BaseActionTypes
可能不是我想做的事情的正确约束类型?最初 extends
似乎是正确的,因为 ExtendedActionTypes
是 BaseActionTypes
的 "extension",但是从 class 继承的角度考虑这一点让我意识到 extends
可能不是这样做的正确方法。 (即,如果 class A 扩展 class B,则 A 拥有 B 中的所有字段,再加上更多。而 ExtendedActionTypes
和 BaseActionTypes
之间的关系不正确。
是否有更好的方法来表达对可区分联合的约束,例如对两个可区分联合类型 X 和 Y 说 "X must by a superset of Y"?
通用类型在这里如何与 extend
一起工作是我们限制我们的 class 最终将包含来自 BaseActionTypes
的一个或多个可能的成员。对于 union types extends 意味着 - 所有可分配给该类型的东西,这意味着它可以具有相同数量或更少的变体,但仅此而已。你问你的类型 ExtendedActionTypes
如果它有一个选项 more .. 真的不是,那只是因为你没有填写类型的实现,这三个都和 TS 一样是结构类型语言。如果你添加到这些类型和属性你将有一个错误,check this here.
所以 ExtendedActionTypes
不能分配给 BaseActionTypes
因为它有更多的选择。
你的错误虽然有不同的原因,因为你试图将类型 Walk
的值设置为 ActionTypes extends BaseActionTypes
的值。这意味着 ActionTypes
是不包含 Walk
的可能类型,因此您无法执行此类赋值。证明下方:
// no error as `Run` extends `BaseActionTypes`
class ExtendedActionDoer extends ActionDoer<Run> {
}
如您所见,Walk
无法分配给 Run
。
可能的问题修复之一是从 class 中完全删除约束:
type ExtendedActionTypes = BaseActionTypes | Jump;
class ActionDoer {
doAction<ActionType extends BaseActionTypes>(a: ActionType) {
}
walk() {
const w: Walk = {type: 'Walk'};
this.doAction(w);
}
}
class ExtendedActionDoer extends ActionDoer {
doAction(a: ExtendedActionTypes) {
}
}
const extendedActionDoer = new ExtendedActionDoer();
const j: Jump = {type: 'Jump'};
extendedActionDoer.doAction(j);
我们也可以保留通用但需要属性,考虑:
type ExtendedActionTypes = Jump;
class ActionDoer<ActionType> {
doAction(a: ActionType | BaseActionTypes) {
}
walk() {
const w: Walk = {type: 'Walk'};
this.doAction(w);
}
}
class ExtendedActionDoer extends ActionDoer<ExtendedActionTypes> {
doAction(a: ExtendedActionTypes) {
}
}
const extendedActionDoer = new ExtendedActionDoer();
const j: Jump = {type: 'Jump'};
extendedActionDoer.doAction(j);
最重要的部分是 - doAction(a: ActionType | BaseActionTypes)
我是说无论你给我什么,我都会接受,但总会有 BaseActionTypes
的成员。