TypeScript能否对自定义type类型实现反射获取结构元数据?
原生TypeScript 无法直接实现你要的针对type类型别名的运行时反射能力。
核心原因是TypeScript的类型系统仅在编译阶段生效,所有type、interface这类类型构造在编译为JavaScript的过程中会被完全擦除,运行时不存在对应类型的任何元数据,自然没法直接读取到属性名、可选性、字段类型这类信息。
虽然原生不支持,但可以通过以下几种方案达到完全相同的效果:
1. 运行时Schema方案(工程成本最低)
不要先定义TS类型再尝试获取反射信息,反过来先定义运行时可读取的Schema结构,再从Schema反向推导TS类型,就能同时满足编译期类型校验和运行时元数据读取的需求,Zod、io-ts这类库都是为这个场景设计的。
举个Zod实现示例:
import { z } from "zod"; // 先定义运行时可识别的枚举和对象Schema const eNumSchema = z.nativeEnum({ FOO: 0, BAR: 1 } as const); const fooSchema = z.object({ bar: z.string(), baz: z.number().optional(), qux: eNumSchema.optional() }); // 反向推导TS类型,和你原本定义的type foo完全等价 type foo = z.infer<typeof fooSchema>; // 运行时直接遍历Schema就能生成你需要的元数据结构 const metadata = { name: "foo", members: Object.entries(fooSchema.shape).map(([key, schema]) => ({ key, optional: schema.isOptional(), definition: schema === eNumSchema ? "eNum" : schema._def.typeName.toLowerCase() })) };
这种方案不需要额外配置TS编译工具链,类型和元数据自动对齐,不会出现改了类型忘了同步元数据的问题,是目前工业界最常用的实现方式。
2. 编译期AST静态分析
如果你一定要保留先写type的代码风格,可以开发自定义TS Transformer(转换器),在编译阶段扫描TS代码的AST(抽象语法树),识别你定义的枚举和type结构,自动生成对应的元数据代码插入到编译产物中,运行时就可以直接读取预生成的元数据。
这种方案灵活度最高,但开发和维护成本很高,需要自行处理类型引用、泛型、嵌套类型等各种复杂场景,也可以直接用ts-morph这类封装好的TS AST处理库减少重复工作量。
3. 改用Class+装饰器实现
如果你可以把type别名改成Class定义,可以配合reflect-metadata库,开启TS的emitDecoratorMetadata编译选项,通过装饰器标记类属性,运行时读取元数据。
但这种方案有明显局限:默认生成的装饰器元数据只能识别基础类型(string/number/boolean)的信息,枚举、自定义引用类型拿到的信息非常模糊,可选属性也需要额外加装饰器标记,灵活度远低于前两种方案。
注:你给出的预期元数据示例里最后一个成员的key存在笔误,应该是
qux而不是bar。
内容的提问来源于stack exchange,提问作者CoryG

