【问题标题】:Typescript: Generic type that extends a generic type on another classTypescript:在另一个类上扩展泛型类型的泛型类型
【发布时间】:2018-06-03 09:53:34
【问题描述】:

例子

class BaseOptions {
    a: 1;
}

class OptionsA extends BaseOptions {
    b: 2;
}

class OptionsB extends BaseOptions {
    c: 3;
}

class Child<TOptions extends BaseOptions> {
    options: TOptions;
}

// Parent must use a child that supports TOptions
class Parent<TOptions extends BaseOptions, TChild extends Child<TOptions>> { }

// Supports OptionsA
class StrictChild extends Child<OptionsA> { }
// Supports OptionsA and OptionsB
class FlexibleChild extends Child<OptionsA | OptionsB> {
    doSomething() {
        if (this.options instanceof OptionsA) {
            const test1 = this.options.b;
        }
        // This should fail because no instanceof check
        const test2 = this.options.c;
    }
}

// Expected to fail because StrictChild can't have OptionsB
const parentA = new Parent<OptionsB, StrictChild>();
// Expected to pass because FlexibleChild can have OptionsA or OptionsB
// but fails because "OptionsA" is not assignable to "OptionsA | OptionsB"
const parentB = new Parent<OptionsB, FlexibleChild>();

我认为问题是

class Parent<TOptions extends BaseOptions, TChild extends Child<TOptions>> { }

特别是Child&lt;TOptions&gt;,因为我认为它需要类似于Child&lt;TOptions extends Child&lt;T&gt;&gt;,但我不知道该怎么做。

Typescript playground

【问题讨论】:

  • 这不符合预期吗? OptionsA | OptionsB 表示子级可以拥有 options 属性,即 OptionsA,因此与 Parent&lt;OptionsB, FlexibleChild&gt; 中的 OptionsB 不兼容。灵活的孩子不会是FlexibleChild extends Child&lt;OptionsA &amp; OptionsB&gt;吗?也就是说,目前,FlexibleChild 更像是一个不知名的孩子,这就是问题所在 - TypeScript 不知道 options 是否是 OptionsB
  • @cartant 嗯,我认为这不太对,如果您使用 & 那么您可以使用 this.options.bthis.options.c 而不检查它们是否存在。其目的是 FlexibleChild 支持 OptionsA 或 OptionsB 但不能同时支持两者。
  • 如果 OptionsA 是一个类,我的示例可能更有意义,因此您可以检查 instanceof
  • 如果是这种情况,错误是完全合适的,你不能做你想做的事。您必须使用const parentAorB = new Parent&lt;OptionsA | OptionsB, FlexibleChild&gt;(); 之类的东西,因为不能保证孩子拥有options 属性,即OptionsB
  • 但是我们不能通过传递允许 OptionsB 的 FlexibleChild 来保证吗?也许我的结构是错误的。 Parent 将接收 options 对象,然后使用 options 对象创建一个 FlexibleChild 实例。我只想检查传递给 Parent 的选项类和子类是否兼容。

标签: typescript


【解决方案1】:

我认为只要我在 Child 上设置默认泛型以便我可以使用 TChild['options']

,它就可以工作了
class Child<TOptions extends BaseOptions = BaseOptions> {
    options: TOptions;
}

// Parent must use a child that supports TOptions
class Parent<TOptions extends TChild['options'], TChild extends Child> { } 

Typescript Playground

编辑

或者你可以这样做

class Parent<TOptions extends TChild['options'], TChild extends Child<BaseOptions>> { }

【讨论】:

    【解决方案2】:

    您正在寻找交集类型,而不是联合类型!

    // Supports OptionsA and OptionsB
    class FlexibleChild extends Child<OptionsA & OptionsB> { }
    

    现在这是一个完全有效的陈述:

    const parentB = new Parent<OptionsB, FlexibleChild>();
    

    参考:https://www.typescriptlang.org/docs/handbook/advanced-types.html

    交集类型将多种类型组合为一种。这允许您将现有类型添加在一起以获得具有您需要的所有功能的单一类型。例如,Person &amp; Serializable &amp; LoggablePersonSerializableLoggable。这意味着这种类型的对象将具有所有三种类型的所有成员。

    【讨论】:

    • 我认为这很接近,但请参阅我对这个问题的评论。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-09
    • 1970-01-01
    • 2020-09-12
    • 2019-05-30
    • 2021-06-01
    相关资源
    最近更新 更多