Skip to content

装饰器stage2配合设置元数据

✍️ w 🕒 2024-06-21 15:59:59(21 hours ago) 🔗 A.前端知识整理

reflect-metadata 是一个 JavaScript 库,用于在运行时访问和操作装饰器的元数据。它提供了一组 API,可以读取和写入装饰器相关的元数据信息。

我们可以将 类 上一些数据进行收集,收集后进行标记。让器具备模型特定自定义属性

  • class 装饰target 是构造函数
  • 静态属性,则为类本身;如果是实例属性,则为类的原型
  • 如果是静态方法,则为类本身;如果是实例方法,则为类的原型

下面用到 Reflect.metadata 他的本质其实是

ts

function metadata(metadataKey,metadataValue){
	return function(target,key){
			Reflect.defineMetadata(metadataKey, metadataValue, target, key);
	}
}

正因如此 Reflect.getMetadata 是获取原型链上的 绑定的因此通过 对象也可以直接获取内容,相对class 装饰器则需要构造函数因为 他的target 并不是原型链

ts
import "reflect-metadata";

@Reflect.metadata("class", "classValue")
class A {
  @Reflect.metadata("property", "propertyValue")
  name: string;

  @Reflect.metadata("method", "methodValue")
  getName() {
    return this.name;
  }
}

const a = new A();

const classValue = Reflect.getMetadata("class", A);
console.log(`Class metadata value: ${classValue}`);
const propertyValue = Reflect.getMetadata("property", a, "name");
console.log(`Property metadata value: ${propertyValue}`);
const methodValue = Reflect.getMetadata("method", a, "getName");
console.log(`Method metadata value: ${methodValue}`);

const classValue1 = Reflect.getMetadata("class", a.constructor);
console.log(`Class metadata value: ${classValue1}`);
const propertyValue1 = Reflect.getMetadata("property", a, "name");
console.log(`Property metadata value: ${propertyValue1}`);
const methodValue1 = Reflect.getMetadata("method", a, "getName");
console.log(`Method metadata value: ${methodValue1}`);


// Class metadata value: classValue
// Property metadata value: propertyValue
// Method metadata value: methodValue
// Class metadata value: classValue
// Property metadata value: propertyValue
// Method metadata value: methodValue

但如果都想获取原型链的可以进行适当自定义封装的装饰

ts emitDecoratorMetadata

在ts 还帮你自动收集 一些其他信息需要你开启 emitDecoratorMetadata

  1. design:type:用于属性的类型元数据。
  2. design:paramtypes:用于构造函数或方法参数的类型元数据。
  3. design:returntype:用于方法的返回类型元数据
ts
import 'reflect-metadata';
// 类装饰器
function classDecorator(target: any) {

}
// 参数装饰器
function paramDecorator(target: any, propertyKey: string, parameterIndex: number) {

}
// 属性装饰器
function propDecorator(target: any, propertyKey: string) {

}
// 方法装饰器
function methodDecorator(target: any, propertyKey: string, descriptor: PropertyDescriptor) {

}
@classDecorator
class Example {
    @propDecorator
    myProperty: string;
    constructor(@paramDecorator serviceA: string, @paramDecorator serviceB: string) {
        console.log('Example instance created');
    }
    @methodDecorator
    myMethod(): string {
        return 'hello';
    }
}
// 获取属性的类型元数据
const propertyType = Reflect.getMetadata('design:type', Example.prototype, 'myProperty');
console.log('Property type:', propertyType.name);
const paramTypes = Reflect.getMetadata('design:paramtypes', Example);
console.log('Constructor param types:', paramTypes.map((type: any) => type.name));
const returnType = Reflect.getMetadata('design:returntype', Example.prototype, 'myMethod');
console.log('Method return type:', returnType.name);

案例

js
const formatMetadataKey = Symbol("format");
function format(formatString: string) {
  return Reflect.metadata(formatMetadataKey, formatString);
}
function getFormat(target: any, propertyKey: string) {
  return Reflect.getMetadata(formatMetadataKey, target, propertyKey);
}

class Greeter {
  @format("Hello, %s")
  greeting: string;
  constructor(message: string) {
    this.greeting = message;
  }
  greet() {
    let formatString = getFormat(this, "greeting");
    return formatString.replace("%s", this.greeting);
  }
}

const objG = new Greeter("world");
// console.log(objG.greet()); // "Hello, world"

const objG = new Greeter("world");
// console.log(objG.greet());

// greet封装在外面也是一样的道理
function greet(obj: any, key: string) {
  let formatString = getFormat(obj, key);
  return formatString.replace("%s", obj[key]);
}

const g = greet(objG, "greeting");
console.log(g);

Released under the MIT License.