打字稿泛型类参数
Posted
技术标签:
【中文标题】打字稿泛型类参数【英文标题】:Typescript generic class parameters 【发布时间】:2018-05-02 15:37:24 【问题描述】:我目前正在为项目编写一些内部抽象类,我需要它是通用的(我希望它是可扩展的)。
我希望调用我的类,因为它会扩展像 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()
我没有找到任何关于从允许在其中包含参数的模板类扩展的信息。
【问题讨论】:
澄清一下:你想扩展 Sample您不能在 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();
【讨论】:
不确定为什么要将方法从构造函数原型复制到 mixin 原型。 mixinextends
构造函数不会自动实现这一点吗?
@jcalz 构造函数将是库基类(例如 vue),mixin 是示例类。所以DerivedComponent通过继承从库基类中获取方法,Sample通过复制获取方法
哦,对不起,我现在明白了。
感谢您的回答。 @jcalz 方法比我现在预期的要多,但你的观点将来可能对我有用。【参考方案2】:
我认为@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()
祝你好运!
【讨论】:
这绝对是我需要的。感谢您的解释!以上是关于打字稿泛型类参数的主要内容,如果未能解决你的问题,请参考以下文章