棘手的装饰器 class
Tricky decorator class
我有以下代码片段,我发现它很难理解:
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();
}
});
};
}
我很难理解上面的代码并理解以下内容:
模型 returns 类型 T(我知道泛型是什么所以不用担心解释泛型)其中
T extends { new(...args: any[]): {}
以上是什么意思?是否要保留现有属性以及额外添加的功能?
另外可以解释一下return函数的类型吗?我们是否要向 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
必须是构造函数(即class)。构造函数参数和 return 类型无关紧要(T
可以有任意数量的参数并且可以 return 扩展 {}
的任何类型,实际上是任何对象类型).
如果直接调用,T
将是 class。用于键入此装饰器的方法基本上是 mixin 的方法(针对 typescript here 进行了描述)。
函数的 return 值将是 new class 继承修饰的 class。因此,它不是添加构造函数,而是用新构造函数替换原始构造函数,并通过 super
调用调用原始构造函数。
在我看来,在这种情况下,泛型有点矫枉过正。它们对 mixins 很有用,因为它们将原始 class 从输入参数转发到输出参数(并且 mixin 将成员添加到类型)。但是由于装饰器不能改变类型的结构,所以没有什么可以转发的。此外,而不是构造函数 returning {}
我将其键入 return 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,return类型声明,{}
表示一个对象需要returned。 TypeScript 将假定 returned 对象没有任何属性。
匿名 Class 在 Return
至于return类型:由于Model
装饰器函数是class装饰器,它可以return一个class本身。如果它 return a class,将使用 class 而不是修饰的 class.
If the class decorator returns a value, it will replace the class declaration with the provided constructor function.
例如:
// `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"
我有以下代码片段,我发现它很难理解:
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();
}
});
};
}
我很难理解上面的代码并理解以下内容:
模型 returns 类型 T(我知道泛型是什么所以不用担心解释泛型)其中
T extends { new(...args: any[]): {}
以上是什么意思?是否要保留现有属性以及额外添加的功能?
另外可以解释一下return函数的类型吗?我们是否要向 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
必须是构造函数(即class)。构造函数参数和 return 类型无关紧要(T
可以有任意数量的参数并且可以 return 扩展 {}
的任何类型,实际上是任何对象类型).
如果直接调用,T
将是 class。用于键入此装饰器的方法基本上是 mixin 的方法(针对 typescript here 进行了描述)。
函数的 return 值将是 new class 继承修饰的 class。因此,它不是添加构造函数,而是用新构造函数替换原始构造函数,并通过 super
调用调用原始构造函数。
在我看来,在这种情况下,泛型有点矫枉过正。它们对 mixins 很有用,因为它们将原始 class 从输入参数转发到输出参数(并且 mixin 将成员添加到类型)。但是由于装饰器不能改变类型的结构,所以没有什么可以转发的。此外,而不是构造函数 returning {}
我将其键入 return 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,return类型声明,{}
表示一个对象需要returned。 TypeScript 将假定 returned 对象没有任何属性。
匿名 Class 在 Return
至于return类型:由于Model
装饰器函数是class装饰器,它可以return一个class本身。如果它 return a class,将使用 class 而不是修饰的 class.
If the class decorator returns a value, it will replace the class declaration with the provided constructor function.
例如:
// `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"