You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何检测函数内部定义类的instanceof?(TypeScript装饰器场景)

问题:如何正确检测装饰器内部类的instanceof?

场景与问题

尝试导出装饰器内部定义的GameCameraComponent类,先通过export declare class声明该类,再在Camera装饰器函数中返回同名内部类。但在CameraService中使用o instanceof GameCameraComponent检测实例时,出现以下错误:

错误信息

  1. webpack编译错误:

无法在'../decorators'中找到导出的'GameCameraComponent'(已作为'GameCameraComponent'导入),可用导出项:Camera、GameObject、ObjectChild、ObjectChildren、Path、Prefab

  1. 控制台运行时错误:

未捕获的类型错误:'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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 18:05:34