如何获取TypeScript类实例各属性对应的装饰器信息
实现方案
TypeScript 本身不会自动存储装饰器与属性的关联信息,你需要在实现装饰器时手动把装饰器信息写入元数据,后续遍历属性时从元数据中读取即可,需要借助reflect-metadata库完成元数据操作。
1. 前置配置
首先安装依赖:
npm install reflect-metadata
修改tsconfig.json开启装饰器相关配置:
{ "compilerOptions": { "experimentalDecorators": true, "emitDecoratorMetadata": true } }
在项目入口文件顶部引入依赖:
import 'reflect-metadata';
2. 实现带元数据存储的装饰器
定义全局唯一的元数据key避免命名冲突,在每个装饰器触发时,把装饰器类型、参数等信息存入对应属性的元数据中:
// 元数据存储key,全局唯一 const DECORATORS_META_KEY = 'custom:property-decorators'; // @key 装饰器实现 function key(target: Object, propertyKey: string | symbol) { // 读取该属性已有的装饰器列表,无则初始化空数组 const existDecos = Reflect.getMetadata(DECORATORS_META_KEY, target, propertyKey) || []; existDecos.push({ type: 'key' }); // 写入元数据 Reflect.defineMetadata(DECORATORS_META_KEY, existDecos, target, propertyKey); } // @maxlength 装饰器实现 function maxlength(length: number) { return function(target: Object, propertyKey: string | symbol) { const existDecos = Reflect.getMetadata(DECORATORS_META_KEY, target, propertyKey) || []; existDecos.push({ type: 'maxlength', params: length }); Reflect.defineMetadata(DECORATORS_META_KEY, existDecos, target, propertyKey); } }
3. 遍历属性读取装饰器信息
方式1:遍历实例属性(要求属性有初始赋值)
如果类的属性有初始值,实例化后可以直接用for...in遍历:
class User { @key id: number = 0; // 给初始值,实例化后可被遍历到 @maxlength(50) Name: string = ''; // 给初始值 } const user = new User(); for (const property in user) { // 从类原型上读取该属性的装饰器元数据 const decorators = Reflect.getMetadata(DECORATORS_META_KEY, User.prototype, property); console.log(`属性${property}的装饰器列表:`, decorators); // 示例:判断属性是否有@key装饰器 const hasKey = decorators?.some(item => item.type === 'key') ?? false; console.log(`属性${property}是否带@key装饰器:`, hasKey); }
方式2:遍历类声明的所有属性(无需属性初始化)
如果不想给属性加初始值,可以直接遍历类原型上的属性,不需要依赖实例:
class User { @key id: number; @maxlength(50) Name: string; } // 获取类上所有声明的属性,过滤掉constructor const allProperties = Reflect.ownKeys(User.prototype).filter(key => key !== 'constructor'); for (const property of allProperties) { const decorators = Reflect.getMetadata(DECORATORS_META_KEY, User.prototype, property); console.log(`属性${String(property)}的装饰器列表:`, decorators); }
注意事项
- 元数据是存在类原型上的,和实例无关,所有实例共享同一份装饰器信息,不需要重复读取
- 你可以根据需求自定义存入元数据的装饰器信息结构,比如增加更多参数、标识位等
内容的提问来源于stack exchange,提问作者Akelmj
相关产品推荐
相关产品推荐

