TypeScript 5中如何通过属性装饰器获取类构造函数?
TypeScript 5属性装饰器无法获取类构造函数的解决方案
TypeScript 5 中属性装饰器遵循 TC39 新提案,参数结构发生变化:第一个参数固定为 undefined,无法直接获取类构造函数。新类型定义如下:
type ClassFieldDecorator = (value: undefined, context: { kind: "field"; name: string | symbol; access: { get(): unknown, set(value: unknown): void }; static: boolean; private: boolean; }) => (initialValue: unknown) => unknown | void;
而旧版(实验性装饰器)中,属性装饰器第一个参数是类构造函数(静态属性)或类原型(实例属性):
function myPropertyDecorator(target: Object, propertyKey: string) { // 处理逻辑 }
对于需要在类级别操作(比如存储验证规则映射)的库,以下是几种可行解决方案:
1. 在初始化函数中通过实例/类本身获取构造函数
新装饰器返回的初始化函数中,this 指向类实例(实例字段)或类构造函数(静态字段),可以借此获取类构造函数:
实例字段场景
function validateField(options: any) { return (value: undefined, context: ClassFieldDecoratorContext) => { return function(initialValue: unknown) { // 通过实例的constructor属性获取类构造函数 const classConstructor = this.constructor; // 存储验证规则到类构造函数上 if (!classConstructor.validationRules) { classConstructor.validationRules = {}; } classConstructor.validationRules[context.name as string] = options; return initialValue; }; }; } class User { @validateField({ required: true }) username: string; @validateField({ min: 18 }) age: number; } // 访问类级别的验证规则 console.log(User.validationRules); // 输出: { username: { required: true }, age: { min: 18 } }
静态字段场景
静态字段的初始化函数中,this 直接指向类构造函数:
function staticFieldDecorator() { return (value: undefined, context: ClassFieldDecoratorContext) => { return function(initialValue: unknown) { // this就是类构造函数 console.log(`静态字段所属类: ${this.name}`); return initialValue; }; }; } class Config { @staticFieldDecorator() static apiUrl: string = "https://api.example.com"; }
2. 继续使用实验性装饰器
如果暂时不想适配新提案,可以在 tsconfig.json 中开启实验性装饰器模式,沿用旧版参数结构:
{ "compilerOptions": { "experimentalDecorators": true, // 其他配置... } }
对应的装饰器写法:
function validateField(options: any) { return (target: Object, propertyKey: string) => { // 区分实例属性和静态属性,获取类构造函数 const classConstructor = target instanceof Function ? target : target.constructor; if (!classConstructor.validationRules) { classConstructor.validationRules = {}; } classConstructor.validationRules[propertyKey] = options; }; } class User { @validateField({ required: true }) username: string; @validateField({ min: 18 }) age: number; }
注意:实验性装饰器是过渡特性,未来可能被移除,长期维护建议适配新提案。
3. 结合类装饰器与属性装饰器
通过类装饰器获取类构造函数,配合属性装饰器收集字段元数据,实现类级别操作:
// 存储字段验证规则的元数据容器 const validationMetadata = new Map<Function, Record<string, any>>(); function validateField(options: any) { return (value: undefined, context: ClassFieldDecoratorContext) => { // 返回初始化函数,关联字段规则与类构造函数 return function(initialValue: unknown) { const constructor = this.constructor; if (!validationMetadata.has(constructor)) { validationMetadata.set(constructor, {}); } validationMetadata.get(constructor)![context.name as string] = options; return initialValue; }; }; } // 类装饰器:处理类级别的逻辑 function validateClass() { return (value: undefined, context: ClassDecoratorContext) => { const constructor = context.metadata as unknown as Function; const rules = validationMetadata.get(constructor); if (rules) { console.log(`类 ${context.name} 的验证规则:`, rules); // 这里可以执行类级别操作,比如注册验证器 } }; } @validateClass() class User { @validateField({ required: true }) username: string; @validateField({ min: 18 }) age: number; }
也可以使用 Reflect.metadata 标准API来管理元数据(需引入 reflect-metadata 库):
import 'reflect-metadata'; const VALIDATION_RULES_KEY = Symbol('VALIDATION_RULES'); function validateField(options: any) { return (value: undefined, context: ClassFieldDecoratorContext) => { return function(initialValue: unknown) { const constructor = this.constructor; // 读取已有规则并更新 const existingRules = Reflect.getMetadata(VALIDATION_RULES_KEY, constructor) || {}; existingRules[context.name as string] = options; Reflect.defineMetadata(VALIDATION_RULES_KEY, existingRules, constructor); return initialValue; }; }; } class User { @validateField({ required: true }) username: string; @validateField({ min: 18 }) age: number; } // 获取类验证规则 const rules = Reflect.getMetadata(VALIDATION_RULES_KEY, User); console.log(rules);
内容的提问来源于stack exchange,提问作者Ivan Mushketyk
相关产品推荐
相关产品推荐

