繁体   English   中英

如何为可区分联合的超集制定通用约束

[英]How do I make a generic constraint for a superset of a discriminated union

在定义泛型类Foo<X> ,其中 X 旨在成为可区分联合类型,有没有办法表达“X 必须是可区分联合 Y 的超集”?

我有一种情况,我使用有区别的联合来表示不同的动作类型。 这个真实世界的上下文是一个使用 Redux 的应用程序,所以每个动作都是不同类型的,具有不同的有效载荷,而 Redux reducer 是一个可以接受任何动作的函数,所以我使用动作类型的可区分联合来描述动作参数。

在下面的示例中,类似于我的实际问题,我有一个可扩展的基类,它知道如何处理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似乎是正确的,因为ExtendedActionTypesBaseActionTypes的“扩展”,但是从类继承的角度考虑这一点让我意识到extends可能不是这样做的正确方法。 (即,如果类 A 扩展了类 B,则 A 具有 B 中的所有字段,以及更多字段。而ExtendedActionTypesBaseActionTypes之间的关系不正确。

有没有更好的方法来表达对可区分联合的约束,为两个可区分联合类型 X 和 Y 说“X 必须由 Y 的超集”?

泛型类型在这里与extend是我们限制我们的类最终将包含来自BaseActionTypes一个或多个可能的成员。 对于联合类型扩展意味着 - 可以分配给类型的所有内容,这意味着它可以具有相同数量或更少的变体,但仅此而已。 你问如果你的类型ExtendedActionTypes有一个更多的选项,那么它如何分配..实际上它不是,这只是因为你没有填写类型的实现,这三个都是一样的,因为 TS 是结构类型化语言. 如果您添加到这些类型和属性中,则会出现错误, 请在此处检查

所以ExtendedActionTypes不能分配给BaseActionTypes因为它有更多的选项而不是更少。

你的错误虽然有不同的原因,因为你试图设置类型的值Walk into value which ActionTypes extends BaseActionTypes 这意味着ActionTypes是不包含Walk可能类型,因此您无法执行此类分配。 证明如下:

// no error as `Run` extends `BaseActionTypes`
class ExtendedActionDoer extends ActionDoer<Run> {
}

如您所见,无法将Walk分配给Run

可能的问题修复之一是完全从类中删除约束:

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成员。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM