我有以下代码片段,我觉得很难理解:
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会保留现有属性还有额外添加的功能?
另外你能解释函数返回类型吗?我们是否在T中添加了额外的构造函数?
(class extends ctr {
constructor(...args: any[]) {
const [data] = args;
if (data instanceof ctr) {
return data;
}
super(...args);
(this as any)._completeInitialization();
}
});
T extends { new(...args: any[]): {} }
意味着T
必须是构造函数(即一个类)。构造函数参数以及返回类型无关紧要(T
可以包含任意数量的参数,并且可以返回任何扩展{}
的类型,实际上是任何对象类型)。
如果直接调用T
将是该类。用于键入此装饰器的方法基本上是mixins(针对typescript here描述)的方法。
函数的返回值将是一个继承装饰类的新类。因此,它不是添加构造函数,而是用新的构造函数替换原始构造函数,并通过super
调用调用原始构造函数。
在我看来,仿制药在这种情况下有点过分。它们对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 { }
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"