【问题标题】:How to extend class with generics combined with mixins in Angular?如何在 Angular 中使用泛型与 mixins 相结合来扩展类?
【发布时间】:2021-10-09 21:37:50
【问题描述】:

背景

我想创建以下结构(蓝色是抽象的,绿色是具体的):

于是我关注this answer 并创建了以下代码:

export abstract class BaseResourceModel {
    public id?: string;
}

type ConcreteClass<C> = new (...args: any[]) => C;

export interface IBaseList<T extends BaseResourceModel>
  extends ConcreteClass<BaseList<T>> {
}

export function TableMixin<T extends BaseResourceModel>() {
  return function <B extends IBaseList<T>>(Base: B){
    class Temporary extends Base implements OnInit {
       (...)
    }
    return Temporary;
  };
}

@Component({ template: '' })
export abstract class BaseList<T extends BaseResourceModel>
  implements OnInit, OnDestroy {
  (...) 
}

@Component({ template: '' })
export abstract class BaseServerList<T extends BaseResourceModel> extends BaseList<T> {
  (...) 
}

问题

我不知道如何创建从 BaseServerList 扩展而来的抽象 BaseServerTable 并由 TableMixin 组成,并在其上保留通用 &lt;T extends BaseResourceModel&gt;。我收到以下错误:

  • 第一次尝试:
class DummyBaseServerList<T> extends BaseServerList<T> { }

@Component({ template: '' })
class BaseServerTable<T> extends TableMixin<BaseResourceModel, typeof DummyBaseServerList>()(BaseServerList<T>) {
  (...)
}

结果:Expected 1 type arguments, but got 2.ts(2558)

  • 第二次尝试:
class DummyBaseServerList<T> extends BaseServerList<T> { }

@Component({ template: '' })
class BaseServerTable extends TableMixin<BaseResourceModel>()(DummyBaseServerList) {
  (...)
}

结果:No base constructor has the specified number of type arguments.ts(2508)

  • 第三次尝试:
@Component({ template: '' })
class BaseServerTable<T> extends TableMixin<BaseResourceModel>()(BaseServerList<T>) {
  (...)
}

结果:Value of type 'typeof BaseServerList' is not callable. Did you mean to include 'new'?ts(2348)

问题

如何实现这种模式?我错过了什么?我到处搜索关于这样的模式的样本

【问题讨论】:

    标签: angular typescript generics subclass mixins


    【解决方案1】:

    我认为你想要的语法是这样的:

    class BaseServerTable<T> extends
        (TableMixin<BaseResourceModel>()(DummyBaseList))<T> { } // okay
    

    TableMixin 是一个泛型函数,只有一个类型参数,没有函数参数。所以你必须把它叫做TableMixin&lt;BaseResourceModel&gt;()。结果是:

    const TMBRM = TableMixin<BaseResourceModel>();
    /* const TMBRM: <B extends IBaseList<BaseResourceModel>>(Base: B) => {
        new (...args: any[]): TableMixin<BaseResourceModel>.(Anonymous function)<B>.Temporary;
        prototype: TableMixin<...>.(Anonymous function)<...>.Temporary;
    } & B */
    

    这是一个接受类构造函数并返回另一个类构造函数的函数。所以你可以给它DummyBaseList(而不是像DummyBaseList&lt;T&gt;这样的东西):

    const TMBRMDBL = TMBRM(DummyBaseList);
    /*const TMBRMDBL: {
        new (...args: any[]): TableMixin<BaseResourceModel>.
           (Anonymous function)<typeof DummyBaseList>.Temporary;
        prototype: TableMixin<...>.(Anonymous function)<...>.Temporary;
    } & typeof DummyBaseList */
    

    所以这是一个类构造函数。它似乎是一个泛型类构造函数,因为它的类型也是可赋值的typeof DummyBaseList,所以我们应该可以使用类型参数对其进行扩展:

    class BST<T> extends TMBRMDBL<T> { } // okay
    

    这在 TypeScript 中有点棘手;通常不能给泛型类构造函数值(如Array)提供泛型类型参数(说const foo = Array&lt;string&gt; 是错误的);只有通用类 interface type 可以做到这一点(所以const bar: Array&lt;string&gt; 可以)。但是当你扩展一个泛型类时,你做在构造函数名称之后放置一个类型参数(如class Foo extends Array&lt;string&gt; { }。


    这就是你如何让代码在没有语法错误的情况下编译。

    请注意,我完全不知道这是否符合您的要求,因为它充满了特定于角度的功能和其他我不是专家的功能。据我所知,在此之后您尝试做的下一件事会严重崩溃...但是对于所提出的问题,这就是答案。

    Playground link to code

    【讨论】:

    • 哇,甚至尝试回答 q +1
    • 谢谢@jcalz,工作完美。顺便问一下,有没有办法去掉DummyBaseList这个类?
    猜你喜欢
    • 2020-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多