如何通过reflect-metadata获取对象属性的具体类型及替代方案?
解决方案:获取TypeScript对象类型详情并生成JSON Schema
首先说明问题根源:reflect-metadata的design:type元数据只能识别内置基础类型(如String、Array等构造函数),对于匿名对象类型,TypeScript编译后会丢失具体结构信息,所以只能拿到顶层的Object类型。
下面提供两种可行的解决方向:
一、构建时获取类型信息(推荐)
TypeScript在编译阶段完整保留类型信息,可借助编译工具或API直接从源码提取结构:
1. 用TypeScript Compiler API解析源码
写一个预处理脚本,遍历类文件的AST(抽象语法树),直接读取body属性的完整类型结构:
import * as ts from 'typescript'; // 初始化编译程序 const program = ts.createProgram(['./src/your-class-file.ts'], { strict: true, target: ts.ScriptTarget.ESNext }); const sourceFile = program.getSourceFile('./src/your-class-file.ts'); if (!sourceFile) return; // 遍历AST查找目标类和body属性 ts.forEachChild(sourceFile, node => { if (ts.isClassDeclaration(node)) { node.members.forEach(member => { if (ts.isPropertyDeclaration(member) && member.name.getText() === 'body') { const typeNode = member.type; if (typeNode && ts.isTypeLiteralNode(typeNode)) { // 提取body的所有子属性类型 typeNode.members.forEach(typeMember => { if (ts.isPropertySignature(typeMember)) { const propName = typeMember.name.getText(); const propType = typeMember.type?.getText(); console.log(`body.${propName}: ${propType}`); } }); } } }); } });
这个脚本可以在项目构建前执行,拿到完整类型结构后直接生成JSON Schema。
2. 用第三方工具typescript-json-schema
这个工具可以直接根据TypeScript类型生成标准JSON Schema,无需自己解析AST:
先安装依赖:
npm install typescript-json-schema --save-dev
然后写脚本生成Schema:
import * as TJS from 'typescript-json-schema'; // 配置选项 const settings = { required: true, // 标记必填字段 }; const compilerOptions = { strictNullChecks: true, }; // 生成目标类的JSON Schema const schema = TJS.generateSchema('./src/your-class-file.ts', 'MyClass', settings, compilerOptions); console.log(JSON.stringify(schema, null, 2));
它会自动识别MyClass中body属性的所有子类型,输出完整的JSON Schema。
二、运行时替代方案
如果必须在运行时获取类型,需要将匿名对象改为显式结构:
1. 定义显式类代替匿名对象
把body的类型抽成独立类,配合reflect-metadata和装饰器递归获取类型:
import 'reflect-metadata'; class BodyType { name!: string; address!: string; favouriteThings!: string[]; } const MyPropertyDecorator = (): PropertyDecorator => { return (target, property) => { const type = Reflect.getMetadata('design:type', target, property); console.log(`${property} 类型构造函数: ${type.name}`); // 可以进一步遍历BodyType的属性元数据,获取子类型 }; }; class MyClass { @MyPropertyDecorator() body!: BodyType; }
2. 用自定义装饰器标记子属性
如果不想额外定义类,可以给属性添加装饰器来记录类型:
import 'reflect-metadata'; // 自定义装饰器,标记属性类型 const PropType = (type: any) => { return (target: any, propertyKey: string) => { Reflect.defineMetadata('prop:type', type, target, propertyKey); }; }; // 定义带元数据的Body类 class Body { @PropType(String) name!: string; @PropType(String) address!: string; @PropType(Array) favouriteThings!: string[]; } class MyClass { body!: Body; } // 运行时读取元数据 const bodyInstance = new Body(); Object.keys(bodyInstance).forEach(key => { const type = Reflect.getMetadata('prop:type', Body.prototype, key); console.log(`body.${key} 类型: ${type.name}`); });
内容的提问来源于stack exchange,提问作者Pezholio
相关产品推荐
相关产品推荐

