如何基于静态成员生成类型,避免重复定义ECSY系统的queries?
解决ECSY中System类queries静态与实例类型重复定义的问题
你可以通过TypeScript的typeof操作符结合映射类型,完全复用静态queries的结构来推导实例queries的类型,不需要手动重复每个属性定义。
基础实现代码
import { System, Entity } from 'ecsy'; // 假设你的组件类定义如下 class Object3D {} class Interactable {} class Camera {} export class PointerSystem extends System { // 静态查询定义,加上as const锁定键名的字面量类型 static queries = { interactable: { components: [Object3D, Interactable] }, camera: { components: [Camera] }, } as const; // 通过映射类型自动推导实例queries的结构 queries: { [K in keyof typeof PointerSystem.queries]: { results: Entity[] } }; execute() { // 直接使用推导后的类型,无需担心属性不存在或类型不匹配 this.queries.interactable.results.forEach(entity => { const obj = entity.getComponent(Object3D); const interactable = entity.getComponent(Interactable); // 处理逻辑 }); this.queries.camera.results.forEach(cameraEntity => { const camera = cameraEntity.getComponent(Camera); // 处理逻辑 }); } }
优化:让results类型更精确
如果希望results里的实体类型能体现出它包含哪些组件,可以定义通用类型进一步推导:
// 定义通用类型,关联查询的组件与实体类型 type QueryEntities<T extends { components: any[] }> = Array< Entity & { getComponent<C extends T['components'][number]>(comp: new () => C): C; } >; export class PointerSystem extends System { static queries = { interactable: { components: [Object3D, Interactable] }, camera: { components: [Camera] }, } as const; queries: { [K in keyof typeof PointerSystem.queries]: { results: QueryEntities<typeof PointerSystem.queries[K]> } }; execute() { // 此时调用getComponent时,TypeScript会自动提示可用的组件类型 this.queries.interactable.results.forEach(entity => { // 编辑器会自动补全Object3D和Interactable const obj = entity.getComponent(Object3D); }); } }
核心原理
as const:锁定静态queries的键名和组件数组的字面量类型,避免TypeScript将键名拓宽为string类型,保证映射类型能准确遍历所有查询键。- 映射类型
[K in keyof typeof PointerSystem.queries]:遍历静态queries的所有属性名,为每个属性生成对应的{ results: ... }结构,完全复用静态定义的结构,无需手动重复。
内容的提问来源于stack exchange,提问作者munHunger
相关产品推荐
相关产品推荐

