我有以下代码片段,很难理解:
export class Record{
};
export class RecordMissingExtendsError{
constructor(r:any){
}
}
export function Model() {
return <T extends { new(...args: any[]): {} }>(ctr: T) => {
if (!(ctr.prototype instanceof Record)) {
throw new RecordMissingExtendsError(ctr);
}
return (class extends ctr {
constructor(...args: any[]) {
const [data] = args;
if (data instanceof ctr) {
return data;
}
super(...args);
(this as any)._completeInitialization();
}
});
};
}
我很难理解上面的代码,并且理解如下:
模型返回类型T(我知道什么是泛型,所以不用担心解释泛型),其中
T extends { new(...args: any[]): {}
以上是什么意思?是否要保留现有属性以及额外添加的功能?
此外,您能否解释函数的返回类型?我们是否要在T中添加一个额外的构造函数?
(class extends ctr {
constructor(...args: any[]) {
const [data] = args;
if (data instanceof ctr) {
return data;
}
super(...args);
(this as any)._completeInitialization();
}
});
答案 0 :(得分:1)
T extends { new(...args: any[]): {} }
意味着T
必须是构造函数(即类)。构造函数参数和返回类型无关紧要(T
可以具有任意数量的参数,并且可以返回扩展{}
的任何类型,实际上是任何对象类型)。
如果直接调用T
将是该类。基本上,用于键入此装饰器的方法是mixin的方法(针对打字稿here进行了描述)。
该函数的返回值将是一个继承装饰后的类的 new 类。因此,它不是添加构造函数,而是用新的构造函数替换原始构造函数,并通过super
调用来调用原始构造函数。
在我看来,在这种情况下,仿制药有点矫kill过正。它们对于mixin非常有用,因为它们将原始类从输入参数转发到输出参数(并且mixin将成员添加到类型中)。但是,由于装饰器无法更改类型的结构,因此没有任何可转发的内容。另外,与其构造函数返回{}
,而是键入它以返回Record
,因为您在运行时检查了它,也可能在编译时检查了它:
export class Record{
protected _completeInitialization(): void {}
};
export function Model() {
return (ctr: new (...a: any[]) => Record ) => {
if (!(ctr.prototype instanceof Record)) {
throw new RecordMissingExtendsError(ctr);
}
return (class extends ctr {
constructor(...args: any[]) {
const [data] = args;
if (data instanceof ctr) {
return data;
}
super(...args);
this._completeInitialization(); // no assertion since constructor returns a record
}
});
};
}
@Model()
class MyRecord extends Record { }
@Model()// compile time error, we don't extend Record
class MyRecord2 { }
答案 1 :(得分:1)
T extends { new(...args: any[]): {} }
在这里,类型T
被限制为扩展{ new(...args: any[]): {} }
的任何类型。此处的格式可能会有些混乱-格式正确,类型看起来像这样:
{
new(...args: any[]): {}
}
这描述了所谓的 newable ,这是需要使用new
调用的某种功能对象。例如:
let A: { new(): any; };
A(); // not ok
new A(); // ok
let B: { new(foo: string): any; };
B(); // not ok
new B(); // not ok, param missing
new B('bar'); // ok
...args: any[]
仅仅是rest parameter declaration,返回类型声明{}
意味着需要返回一个对象。 TypeScript将假定返回的对象不具有任何属性。
关于返回类型:由于Model
装饰器函数是类装饰器,因此它可以返回类本身。如果确实返回一个类,则将使用该类而不是修饰的类。
如果类装饰器返回一个值,它将用提供的构造函数替换类声明。
例如:
// `ctr` is a common abbreviation for "constructor"
function Decorate(ctr: Function) {
return class {
constructor() {
super();
console.log('decorated');
}
};
}
@Decorate
class A {
constructor() {
console.log('A');
}
}
new A(); // this will log: "A" first, then "decorated"