TypeScript 如何用泛型实现Entity类按类型从组件列表获取对应实例
这个需求是TypeScript场景下ECS架构的常见实现,核心要注意TypeScript泛型在运行时会被擦除,仅传泛型参数的写法无法在运行时拿到构造函数做instanceof匹配,因此推荐「传入构造函数+泛型自动推导」的实现方式,既满足运行时校验,又能得到正确的类型提示。
基础类型定义
// 所有组件都需要实现的空接口 interface Component {} // 组件构造函数类型约束 type ComponentCtor<T extends Component = Component> = new (...args: any[]) => T
Entity类实现
class Entity { // 内部存储的组件数组 private components: Component[] = [] /** * 根据传入的组件构造函数,查询匹配的组件实例 * @param ctor 目标组件的构造函数 * @returns 匹配到的组件实例,找不到则返回undefined */ getComponent<T extends Component>(ctor: ComponentCtor<T>): T | undefined { return this.components.find(comp => comp instanceof ctor) as T | undefined } /** * 必须找到对应组件的版本,找不到直接抛出错误,避免上层做非空判断 * @param ctor 目标组件的构造函数 * @returns 匹配到的组件实例 */ getRequiredComponent<T extends Component>(ctor: ComponentCtor<T>): T { const comp = this.getComponent(ctor) if (!comp) { throw new Error(`Missing required component: ${ctor.name}`) } return comp } // 配套的添加组件方法 addComponent<T extends Component>(comp: T): void { this.components.push(comp) } }
调用示例
// 自定义业务组件 class MoveComponent implements Component { x = 0 y = 0 speed = 10 } class HealthComponent implements Component { hp = 100 maxHp = 100 } // 实例化Entity使用 const player = new Entity() player.addComponent(new MoveComponent()) player.addComponent(new HealthComponent()) // 自动推导返回类型,不需要手动声明泛型 const move = player.getComponent(MoveComponent) // 类型:MoveComponent | undefined const health = player.getRequiredComponent(HealthComponent) // 类型:HealthComponent
关于仅传泛型的调用方式说明
你提到的e.getSpecificComponent<SpecificComponentClass0>()写法仅能在编译期做类型断言,运行时无法获取到泛型对应的构造函数,没办法做instanceof匹配,属于不安全的实现,不推荐使用。如果一定要做,可以用以下hack写法:
// 不推荐!运行时无校验,仅做类型层面的强制转换,容易出现类型不匹配的运行时错误 getComponentUnsafe<T extends Component>(): T | undefined { // 这里没有任何运行时校验逻辑,完全依赖开发者传入的泛型正确 return this.components[0] as unknown as T | undefined }
内容的提问来源于stack exchange,提问作者baal_imago
相关产品推荐
相关产品推荐

