如何在 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 特定的功能以及我不是专家的其他功能。据我所知,接下来的事情你尝试这样做之后会非常糟糕......但是对于所问的问题,这就是答案。
背景
我想创建以下结构(蓝色是抽象的,绿色是具体的):
所以我按照
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 特定的功能以及我不是专家的其他功能。据我所知,接下来的事情你尝试这样做之后会非常糟糕......但是对于所问的问题,这就是答案。