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

TypeScript:如何为多组件映射的实体生成强类型?

解决方案

要实现将传入的组件数组推导为对应实体类型数组的需求,你需要调整类型工具和函数的类型定义,核心是正确遍历组件数组的每个元素并提取name和type来构建实体类型。

1. 修正类型工具

替换你之前的UnionToIntersection,使用下面的ComponentTupleToEntity工具类型,它会遍历组件数组的每个元素,将每个组件的name作为实体对象的键,type作为对应键的类型:

type ComponentTupleToEntity<T extends Component<any>[]> = {
  [K in T[number] as K['name']]: K['type']
}[]

2. 调整queryEntities函数类型

将函数的返回类型指定为上述工具类型,确保类型推导准确:

function queryEntities<T extends Component<any>[]>(...components: T): ComponentTupleToEntity<T> {
  // 你的实体过滤逻辑示例:
  // 假设这里有一个全局实体列表
  const allEntities = []; 
  const filteredEntities = allEntities.filter(entity => 
    components.every(comp => entity.hasOwnProperty(comp.name))
  );
  return filteredEntities as ComponentTupleToEntity<T>;
}

3. 优化createComponent(可选但推荐)

为了让name的类型推导为具体的字面量类型(而非宽泛的string),可以修改createComponent函数,确保返回的组件对象保留name的字面量类型:

function createComponent<T, N extends string>(name: N, type: T): { name: N; type: T } {
  return { name, type } as const;
}

这样当你创建组件时:

const TransformComponent = createComponent("transform", { x: 0, y: 0 } as const);
const BodyComponent = createComponent("body", { height: 100, width: 100 } as const);

类型推导会更精准,ComponentTupleToEntity能准确识别name的具体值。

验证效果

现在调用queryEntities时,返回的类型会完全符合预期:

const entities = queryEntities(BodyComponent, TransformComponent);
for (const entity of entities) {
  console.log(entity.body.height); // 类型为number
  console.log(entity.transform.x); // 类型为number
}

此时entities的类型就是:

{
  body: { height: number; width: number };
  transform: { x: number; y: number };
}[]

为什么之前的实现失败?

你之前的UnionToIntersection工具类型错误地将整个组件数组作为单个元素进行infer,而没有遍历数组的每个元素。正确的做法是通过T[number]获取数组元素的联合类型,再用as关键字将每个元素的name映射为对象的键。

内容的提问来源于stack exchange,提问作者Jonathon Orsi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.26 16:43:08