如何检测函数内部定义类的instanceof?(TypeScript装饰器场景)
场景与问题
尝试导出装饰器内部定义的GameCameraComponent类,先通过export declare class声明该类,再在Camera装饰器函数中返回同名内部类。但在CameraService中使用o instanceof GameCameraComponent检测实例时,出现以下错误:
错误信息
- webpack编译错误:
无法在'../decorators'中找到导出的'GameCameraComponent'(已作为'GameCameraComponent'导入),可用导出项:Camera、GameObject、ObjectChild、ObjectChildren、Path、Prefab
- 控制台运行时错误:
未捕获的类型错误:'instanceof'的右侧不是对象
相关代码
装饰器定义文件
export declare class GameCameraComponent extends GameObject { isMainCamera: boolean; } export abstract class GameObject<T extends { new(...args: any[]): any; } = any> { } // 装饰器函数 export function Camera(options?: CameraOptions) { return function (target: new () => object) { return class GameCameraComponent extends GameObject { instance = new target(); readonly isMainCamera; // 构造函数中初始化 } } }
检测逻辑代码
export class CameraService { constructor() { const cam = Engine.gameObjects.find(o => o instanceof GameCameraComponent && o.isMainCamera); } }
解决方案
问题根源
export declare class仅声明了类型,没有导出实际的类对象,webpack无法找到对应的实体;装饰器内部的GameCameraComponent是独立的内部类,和外部声明的同名类并非同一个对象,导致instanceof检测时右侧为undefined,触发报错。
方案一:导出实际的内部类引用
修改装饰器文件,将装饰器内部创建的类赋值给外部导出的变量,替代仅类型声明的方式:
export abstract class GameObject<T extends { new(...args: any[]): any; } = any> { } // 先声明变量用于存储装饰器创建的类 export let GameCameraComponent: typeof GameObject; export function Camera(options?: CameraOptions) { return function (target: new () => object) { // 定义内部类 const CameraClass = class GameCameraComponent extends GameObject { instance = new target(); readonly isMainCamera; constructor() { super(); // 初始化isMainCamera(示例逻辑) this.isMainCamera = options?.isMain ?? false; } } // 将内部类赋值给外部导出的变量 GameCameraComponent = CameraClass; return CameraClass; } }
这样外部导入的GameCameraComponent就是装饰器实际生成的类对象,instanceof检测可正常工作,webpack也不会再报错。
方案二:使用自定义标识替代instanceof
如果不想修改类的导出结构,可给装饰器生成的实例添加唯一标识属性,通过检测该属性判断类型:
修改装饰器文件
// 扩展类型声明,添加自定义标识 export declare class GameCameraComponent extends GameObject { isMainCamera: boolean; __isGameCamera: boolean; } export abstract class GameObject<T extends { new(...args: any[]): any; } = any> { } export function Camera(options?: CameraOptions) { return function (target: new () => object) { return class GameCameraComponent extends GameObject { instance = new target(); readonly isMainCamera; // 添加自定义标识 __isGameCamera = true; constructor() { super(); this.isMainCamera = options?.isMain ?? false; } } } }
修改检测逻辑
export class CameraService { constructor() { const cam = Engine.gameObjects.find(o => (o as GameCameraComponent).__isGameCamera && (o as GameCameraComponent).isMainCamera ); } }
这种方式绕开了instanceof的类对象匹配问题,通过自定义属性识别实例类型,适合需要保留原有类型声明结构的场景。
方案对比
- 方案一更符合TypeScript类型系统规范,能保留
instanceof的类型推断能力,推荐优先使用。 - 方案二更灵活,无需调整类的导出引用逻辑,适合快速修复场景。
内容的提问来源于stack exchange,提问作者Get Off My Lawn

