我目前正在为项目编写一些内部抽象类,我需要它是通用的(我希望它是可扩展的)。
我希望调用我的类,因为它会像Sample extends T
那样扩展T模板,以便拥有T
的所有参数。
例如,如果T
是Vue,我会拥有所有Vue参数,例如$el
或$options
,而无需重新声明Vue或包含它。
所以我有以下内容:
export namespace SDK {
export abstract class Sample<T> {
private static methods: any = {
hello: Sample.prototype.hello
}
abstract callMe () : void;
x: number = 0
y: number = 0
width: number = 1
height: number = 1
hello (): void {
console.log('Sample hello world')
this.callMe()
}
}
}
但我不知道如何处理将T的属性包含在Sample中。
我希望它像:
export namespace SDK {
export abstract class Sample<T> {
private static methods: any = {
hello: Sample.prototype.hello
}
abstract callMe () : void;
x: number = 0
y: number = 0
width: number = 1
height: number = 1
// T properties (Vue example)
$el: HTMLElement
...
hello (): void {
console.log('Sample hello world')
this.callMe()
}
}
}
我希望我的班级被称为:
export default class MyComponent extends SDK.Sample<Vue> {
name: string = 'my-component';
callMe () : void {
console.log('called')
}
mounted () : void {
this.hello()
}
}
我没有找到任何关于从允许在其中包含参数的模板化类扩展的内容。
答案 0 :(得分:1)
您无法在Typescript中扩展泛型参数(在C#和Java中也是如此)。你可以做的是使用mixins方法。
根据您的要求,我想出了以下内容。我实际上没有使用Vue进行测试(我没有使用该库进行环境设置)但是方法和属性是从预期的两个类继承的,所以它应该与Vue一起工作(如果你留下评论有任何问题我可以看看他们)。
我发现了两个缺点:
执行魔法的功能
function extendSample<T, R extends { new(): T & Sample }>(componentCtor: new () => T): R {
// Create a new derived class from the component class
class DerivedComponent extends (<new () => any>componentCtor) {
constructor() {
// Call thec omponent constructor
super();
// Call out sample class constructor
Sample.apply(this)
}
}
// Copy instance methods to DerivedComponent
Object.getOwnPropertyNames(Sample.prototype).forEach(name => {
DerivedComponent.prototype[name] = Sample.prototype[name];
});
return <R><any>DerivedComponent;
}
示例代码:
export abstract class Sample {
abstract callMe(): void;
x: number = 0
y: number = 0
width: number = 1
height: number = 1
hello(): void {
console.log('Sample hello world')
this.callMe()
}
}
export class LibaryComponentBase {
constructor() {
this.$el = "HTML "
}
$el: string;
public libraryMethod() {
console.log("libraryMethod");
}
static Test() {
}
}
export default class MyComponent extends extendSample(LibaryComponentBase) {
name: string = 'my-component';
constructor() {
super();
console.log(this.$el);
this.libraryMethod();
this.hello();
}
callMe(): void {
console.log('called')
}
mounted(): void {
this.hello();
}
}
let my = new MyComponent();
my.callMe();
答案 1 :(得分:1)
我认为@TitianCernicovaDragomir基本上使用mixins是正确的。我有类似的代码,我将发布完整性,因为我认为我们采取略有不同的方法,他们有一些不同的优点和缺点。
以下代码确实强制您实现abstract
方法,并允许您访问静态成员。但是你通过使用私人未导出的名称来支付费用,最终阻止你将这个名称作为供其他人使用的库。我认为有一些解决方法,但我不想在这个问题上走得太远。
无论如何,这里是Sample
:
export namespace SDK {
export type Constructor<T> = {
new(...args: any[]): T;
readonly prototype: T;
}
export function Sample<C extends Constructor<{}>>(ctor: C) {
abstract class Sample extends ctor {
private static methods: any = {
hello: Sample.prototype.hello
}
abstract callMe(): void;
x: number = 0
y: number = 0
width: number = 1
height: number = 1
hello(): void {
console.log('Sample hello world')
this.callMe()
}
}
return Sample;
}
}
及其用法:
export default class MyComponent extends SDK.Sample(Vue) {
name: string = 'my-component';
callMe () : void {
console.log('called')
}
mounted () : void {
this.hello()
}
}
祝你好运!