为何typeof检测number|null类型返回'object'?如何获取其完整类型?
如何获取TypeScript属性的声明类型(number|null)?
问题场景
可复现代码:
class MyObject{ id: number|null = null } const a = new MyObject() console.log(typeof a.id)
执行结果:
'object'
问题核心:已知typeof null返回object的原因,但想通过类似反射的方式获取该属性声明的number|null完整类型。
解决方案
TypeScript的类型系统是编译时生效的,编译后的JavaScript代码会完全擦除类型信息,所以直接通过运行时API(比如typeof)无法获取声明的类型。要实现这个需求,需要通过元数据注入的方式,在编译阶段把类型信息保留到运行时。
方法1:使用reflect-metadata(官方推荐的元数据方案)
- 先安装依赖:
npm install reflect-metadata
- 修改
tsconfig.json,启用装饰器和元数据发射:
{ "compilerOptions": { "experimentalDecorators": true, "emitDecoratorMetadata": true } }
- 编写代码:
import 'reflect-metadata'; class MyObject { // 空装饰器触发元数据收集(必须有装饰器才能让TS发射类型元数据) @(() => {}) id: number|null = null; } const a = new MyObject(); // 获取属性的设计类型元数据 const typeConstructor = Reflect.getMetadata('design:type', a, 'id'); console.log(typeConstructor.name); // 输出 "Number"
注意:默认的design:type元数据只能识别单一构造函数类型,对于number|null这种联合类型,它只会返回Number(因为null没有构造函数)。如果需要精准获取number|null的完整声明,需要自定义元数据。
方法2:自定义装饰器存储完整类型信息
如果需要准确保留number|null这类联合类型的声明,可以自己写装饰器来存储类型字符串:
import 'reflect-metadata'; // 自定义装饰器,手动传入类型描述 function Type(type: string) { return (target: any, propName: string) => { Reflect.defineMetadata('custom:type', type, target, propName); }; } class MyObject { @Type('number|null') id: number|null = null; } const a = new MyObject(); const declaredType = Reflect.getMetadata('custom:type', a, 'id'); console.log(declaredType); // 输出 "number|null"
这种方式完全可控,能精准存储你需要的类型信息,但需要手动维护装饰器的类型字符串和TS声明的一致性。
总结
TypeScript本身没有内置的运行时类型反射能力,必须通过编译时注入元数据的方式才能获取声明的类型信息。根据需求选择reflect-metadata的默认元数据,或者自定义装饰器来存储完整类型描述。
内容的提问来源于stack exchange,提问作者E. Williams
相关产品推荐
相关产品推荐

