课程名称: 晋级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");
以上就是这个需求的 实现分析。(写的比较乱)
课程收获:
这两章对“类装饰器”的应用场景和有了一些理解。
理解了"泛型工厂类继承装饰器" 实现 和 意义。