如何在 Angular 中使用泛型结合 mixin 来扩展 class?

How to extend class with generics combined with mixins in Angular?

背景

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

所以我按照 创建了以下代码:

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 扩展并与 TableMixin 保持通用 <T extends BaseResourceModel> 的抽象 BaseServerTable。我收到以下错误:

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)

问题

如何实现这个模式?我缺少什么?我到处都搜索过像这样的模式样本

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

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

TableMixin 是一个泛型函数,只有一个类型参数,没有函数参数。所以你必须像 TableMixin<BaseResourceModel>() 这样称呼它。结果是:

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 */

这是一个接受 class 构造函数和 returns 另一个 class 构造函数的函数。所以你可以给它DummyBaseList(而不是像DummyBaseList<T>这样的东西):

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

所以这是一个 class 构造函数。它似乎是一个通用的 class 构造函数,因为它的类型也是可分配的 typeof DummyBaseList,所以我们应该可以使用类型参数扩展它:

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

这在 TypeScript 中有点棘手;通常,泛型 class 构造函数值 (如 Array)不能被赋予泛型类型参数(说 const foo = Array<string> 是错误的);只有通用 class 接口类型 可以做到这一点(所以 const bar: Array<string> 没问题)。但是当你扩展泛型 class 时,你 do 在构造函数名称之后放置一个类型参数(如 class Foo extends Array<string> { }.


这就是您编译代码时没有语法错误的方法。

请注意,我完全不知道这是否符合您的要求,因为它充满了 angular 特定的功能以及我不是专家的其他功能。据我所知,接下来的事情你尝试这样做之后会非常糟糕......但是对于所问的问题,这就是答案。

Playground link to code