我想写一个带有参数的类装饰器。麻烦的是我想强制执行与类本身相关的参数类型。
class Options<T> {
accept: (instance: T)=>boolean;
}
var MyOptions: Options<MyClass>={
accept: function (instance: MyClass)
{ return true; }
};
@deco(MyOptions)
class MyClass {
y: string;
constructor() {
this.y="Hello";
}
}
另一个目标是我需要对构造函数进行子类化,并赋予它对选项的访问权限,因此整个实现必须写在deco
内。这是我通过试验和充分的错误得到的:
function imported<T>(instance: T, options: Options<T>): any { return {}; }
function deco<T extends {}>(options: Options<T>) {
return function<CtorOfT extends {new(...args:any[]):T}>(ctr: CtorOfT) {
let options_copy: Options<sub>=options;
//replace constructor to add $accepted and $imported
class sub extends ctr {
$accepted: boolean;
$imported: any;
constructor(...args:any[]) {
super(args);
this.$accepted = options_copy.accept(this);
this.$imported = imported<sub>(this, options_copy);
}
};
return sub;
}
}
编译器抱怨行
class sub extends ctr {
这
Base constructor return type 'T' is not a class or interface type.
我尝试用<T extends {}>
解决这个问题,但这并没有太大帮助。它在我替换
new(...args:any[]):T
与
new(...args:any[]):{}
这就是我正在做的事情,但它失去了MyOptions
和MyClass
之间的类型联系。你可以很容易地猜到,我不知道我在做什么(错误)。
链接到使用TSC 2.8.1(Repl)
测试的previous version修改:按类型连接,我的意思是以下内容应该是错误:
class Foo {
x: number;
}
var FooOptions: Options<Foo>={
accept: function (instance: Foo)
{ return true; }
};
@deco(FooOptions) //error, Foo vs MyClass
class MyClass {
...
感谢jcalz,我注意到我将Options.accept声明为通用,但我不应该这样做。编辑出来,但现在抱怨
let options_copy: Options<sub>=options;
也是。我会尝试理解Github #16390 issue的讨论,但这确实令人费解。
答案 0 :(得分:2)
我想现在还没有办法让mixin扩展泛型类型的构造函数,如Microsoft/Typescript#16390中所提到的那样。如果您认为这很重要,您可能想对该问题发表评论或给它一个或者什么。
正如我在评论中提到的那样,你可以断言你摆脱这个问题...你在deco()
的实现中失去了一些类型的安全性,但至少从外部(调用者的#)事情应该有效。这是一种方法:
// name for "Constructor of"
interface Ctor<T> {
new(...args: any[]): T
}
function deco<T>(options: Options<T>) {
// give a name to the extended T we will return
type XT = T & {
$accepted: boolean;
$imported: any;
}
// Use Ctor<T> below
return function <CtorOfT extends Ctor<T>>(ctr: CtorOfT) {
// leave options_copy as Options<T>
let options_copy: Options<T> = options;
// first assertion: ctr as Ctor<any>
const sub = class extends (ctr as Ctor<any>) {
$accepted: boolean;
$imported: any;
constructor(...args: any[]) {
super(args);
// second assestion: this as XT
const that = this as any as XT;
// use that instead of this
this.$accepted = options_copy.accept(that);
this.$imported = imported(that, options_copy);
}
// final assertion: sub as Ctor<XT>
} as Ctor<XT>;
return sub;
}
}
在上文中,deco()
需要Options<T>
并返回一个Ctor<T>
并返回Ctor<XT>
的函数,其中XT
是T
以及您添加到sub
的扩展属性。因此,当您致电deco()
时,您将获得所需的类型安全保障。
好的,那是我能找到你想要的最接近的。希望能帮助到你;祝好运。