课程名称: 晋级TypeScript高手,成为抢手的前端开发人才
课程章节: 10-9~10-10 【泛型工厂类继承装饰器】 泛型工厂类继承装饰器实现
课程讲师: keviny79
课程内容:
类装饰器的应用场景:
需求:对已经开发好的项目中的任何一个类,创建实例时,打印日志信息,输出哪一个类被创建了,并输出传递了哪些参数信息。
代码实现:
/* 需求:对已经开发好的项目中的任何一个类,创建实例时, 打印日志信息, 输出哪一个类被创建了,并输出传递了哪些参数信息 */ // 1.完成日志信息的装饰器 function LoggerInfoDecorator<T extends { new (...args: any): any }>( targetClass: T ) { class LoggerSonClass extends targetClass { constructor(...args: any) { super(...args); console.log("日志信息...targetClass:", targetClass); } } return LoggerSonClass; } // 2. 目标类 @LoggerInfoDecorator class Test { name!: string; age!: number; // 1.先执行原来构造函数 constructor(name: string) { this.name = name; } eat() { console.log(this.name, "吃饭"); } } let test = new Test("aa");
分析:
以下是需求实现的步骤
1.我们需要在“使用”类的时候,进行日志的打印,而不是没有使用类就进行日志的打印,如下:(以下代码是错误的)
// 1.完成日志信息的装饰器 function LoggerInfoDecorator( targetClass: any ) { console.log("日志信息...targetClass:", targetClass.name); } // 2. 目标类 @LoggerInfoDecorator class Test { name!: string; age!: number; // 1.先执行原来构造函数 constructor(name: string) { this.name = name; } eat() { console.log(this.name, "吃饭"); } } //这里没有执行 类,但还是打印了日志信息,是不对的 // let test = new Test("aa");
2.如何做?根据阅读 类装饰器源码,可以知道 类装饰器 最后会返回一个类,后覆盖掉 “目标类”,在把覆盖掉的 类名 导出,之后创建 “目标类” 就会是被覆盖掉的类,如下:
// 2. 目标类 var Test = /** @class */ (function () { // 1.先执行原来构造函数 function Test(name) { this.name = name; } Test.prototype.eat = function () { console.log(this.name, "吃饭"); }; // __decorate() 装饰器的返回值会 赋值给 Test 类,最后导出 Test = __decorate([ LoggerInfoDecorator, __metadata("design:paramtypes", [String]) ], Test); // 导出 return Test; }());
3.利用第2点,我们就可以在“类装饰器中”创建一个“类”,这个“类”专门用于打印 “日志”,之后返回这个类。在“外界 ”创建目标类时,实际是创建“类装饰器中”自己创建的类,如下:(以下代码是错误的)
function LoggerInfoDecorator( targetClass: any ) { class LoggerSonClass { constructor(...args: any) { console.log("日志信息...targetClass:"); } } return LoggerSonClass; } // 2. 目标类 // 这里会提示错误 @LoggerInfoDecorator class Test { name!: string; age!: number; // 1.先执行原来构造函数 constructor(name: string) { this.name = name; } eat() { console.log(this.name, "吃饭"); } } let a = new Test("aa");
4.第3点中的代码是错误的(在js中正确),在阅读源码得知 “类装饰器”中返回的内容最后会赋值给“目标类”,但在ts 中“类装饰器”返回的内容和赋值给“目标类”的内容类型不一样,ts会提示缺少属性。也就是说等号(=)右边必须完全具备 等号(=) 左边的所有属性。
class Test { name!: string; } class targetClass{ age!: string; } let copy = Test; // 错误,右侧属性中缺少左侧的属性 copy = targetClass; //---------------分割线------------------- class Test { name!: string; } class targetClass{ age!: string; name!: string; } let copy = Test; // 正确,右侧属性中包含左侧的属性 copy = targetClass; //---------------分割线------------------- class Test { name!: string; } // 这里使用继承可以得到的获取父类中的属性 class targetClass extends Test{ age!: string; } let copy = Test; // 正确,右侧属性中包含左侧的属性 copy = targetClass;
5.根据第4点可以得知 使用继承 就可以获取父类中属性,之后在把子类赋值给父类就不会出错,所以需求就可以使用类继承完美实现,如下:
// 1.完成日志信息的装饰器 // 这里需要使用 泛型约束为 构造函数 function LoggerInfoDecorator<T extends { new (...args: any): any }>( targetClass: T ) { // targetClass实际上就是目标类 class LoggerSonClass extends targetClass { constructor(...args: any) { super(...args); console.log("日志信息...targetClass:", targetClass); } } // 返回类,这里返回的类会覆盖掉目标类 return LoggerSonClass; } // 2. 目标类 @LoggerInfoDecorator class Test { name!: string; age!: number; // 1.先执行原来构造函数 constructor(name: string) { this.name = name; } eat() { console.log(this.name, "吃饭"); } } // 这里创建的 类 实际上是“类装饰器”中返回的类 let test = new Test("aa");
以上就是这个需求的 实现分析。(写的比较乱)
课程收获:
这两章对“类装饰器”的应用场景和有了一些理解。
理解了"泛型工厂类继承装饰器" 实现 和 意义。