TypeScript访问者模式下类型信息丢失问题求助
解决TypeScript访问者模式中类型信息丢失问题
在JavaScript中,typeof操作符对于类实例始终返回object——因为TypeScript的类编译后本质是基于原型的构造函数,实例都是对象类型。所以你用typeof无法区分Person和Address实例,以下是几种可行的解决方案:
方案1:使用constructor.name获取类名
每个类实例的constructor属性指向其构造函数,而构造函数的name属性就是类的名称(编译后的JavaScript会保留类名,除非代码被压缩混淆)。修改你的访问者代码:
class StrVisitor extends AbsVisitor { public visitPerson(p: Person): void { console.log(`XXX ${p.constructor.name} XXX`) // 输出"Person" console.log(`name: ${p.name}`); } public visitAddress(a: Address): void { console.log(`XXX ${a.constructor.name} XXX`) // 输出"Address" console.log(`{${a.street}}( ${a.num} )`); } }
运行后结果会变成:
XXX Person XXX name: moish XXX Address XXX {5th Ave.}( 62 )
方案2:添加自定义类型标识字段
如果担心代码压缩导致类名被混淆(比如生产环境打包工具会重命名类),可以给每个类添加一个硬编码的类型标识属性:
class Person { readonly type = 'Person'; // 自定义类型标识 constructor(public name: string){} public accept(v: AbsVisitor){ v.visitPerson(this); } } class Address { readonly type = 'Address'; // 自定义类型标识 constructor(public street: string, public num: number){} public accept(v: AbsVisitor){ v.visitAddress(this); } }
然后在访问者中直接读取该属性:
class StrVisitor extends AbsVisitor { public visitPerson(p: Person): void { console.log(`XXX ${p.type} XXX`) // 输出"Person" console.log(`name: ${p.name}`); } public visitAddress(a: Address): void { console.log(`XXX ${a.type} XXX`) // 输出"Address" console.log(`{${a.street}}( ${a.num} )`); } }
这种方法的优势是类型标识完全可控,不受编译或压缩工具的影响,同时TypeScript还能基于这个字段做类型窄化判断。
方案3:利用TypeScript元数据(进阶)
如果你需要更复杂的类型信息,可以启用TypeScript的装饰器和元数据功能:
- 在
tsconfig.json中启用experimentalDecorators和emitDecoratorMetadata - 使用
reflect-metadata库获取类的元数据
不过这种方法相对复杂,适合需要深度类型反射的场景,普通场景前两种方案足够。
内容的提问来源于stack exchange,提问作者OrenIshShalom
相关产品推荐
相关产品推荐

