You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 21:37:57