TypeScript类型错误求助:Entity组件获取逻辑约束异常修复
TypeScript类型约束失效问题排查与修复需求
问题概述
遇到TypeScript类型错误:此表达式不可调用,联合类型的每个成员均无法调用,同时组件获取逻辑的类型校验存在异常。已对齐现有架构实现方案,尽可能降低复杂度,但仍有测试用例未通过,耗时三天亟待解决。
核心问题表现
TypeScript代码中,Entity类的get/has方法、getComponentFromEntity函数的类型约束未按预期生效,具体表现为:
- 在SystemA的onUpdate方法中,调用
e.get(CComponent)未触发预期的类型报错; getComponentFromEntity(ab, CComponent)未触发预期的类型报错,传入AComponent时的报错逻辑也不符合预期。
推测方向
getComponentFromEntity是解决问题的关键,可能需要使用高级类型模式(黑魔法类型)来修复类型约束。
相关代码
//utils types type Constructor<T> = { new(...args: any): T }; type ExtractComponentType<T> = T extends Entity<infer C> ? C : never; type EntitiesCareMap<C extends Component> = Map<number, Entity<C>> type ComponentType<T extends Component = Component> = Constructor<T>; type TupleToInstances3<T extends readonly unknown[]> = { [K in keyof T]: T[K] extends Constructor<infer U> ? U extends {} ? U : never : never; } type ExtractSystemComponents4< S extends Rules, K extends RULES > = S[K] extends ComponentType[] ? S[K] extends never[] ? UnknowComponent : TupleToInstances3<S[K]>[number] : never; interface SystemUpdate<S extends System = System, R extends Rules = S['rules']> { entities: EntitiesCareMap< ExtractSystemComponents4<R, RULES.hasAll> >; } // issue class Entity< C extends Component = Component, > { declare public components: Set<C>; get<T extends C>(componentClass: Constructor<T>): T { return undefined as unknown as T; } has<T extends Component>( componentClass: Constructor<T> ): this is Entity<T> { return false; } } abstract class Component { foo() { } } enum RULES { hasAll, } type Rules = { readonly [K in RULES]?: ComponentType[] }; abstract class System { abstract rules: Rules; abstract onUpdate(t: SystemUpdate<System, Rules>): void; } export class UnknowComponent extends Component { #component!: never; } export class AComponent extends Component { #component!: never; } export class BComponent extends Component { #component!: never; } export class CComponent extends Component { #component!: never; } export class DComponent extends Component { #component!: never; } class SystemA extends System { public rules = { [RULES.hasAll]: [AComponent, BComponent], }; onUpdate({entities}: SystemUpdate<SystemA>) { entities.forEach(( e ) => { e.get(BComponent)// 🟢 预期通过 e.get(AComponent)// 🟢 预期通过 e.get(CComponent)// 🔴 预期报错 if (e.has(CComponent)) { e.get(CComponent)// 🟢 预期通过 e.get(DComponent)// 🔴 预期报错 if (e.has(DComponent)) { e.get(DComponent)// 🟢 预期通过 } } }); } } declare const ab: Entity<BComponent> | Entity<BComponent | CComponent>; /** Get a components from entity */ function getComponentFromEntity<E extends Entity, C extends ExtractComponentType<E>>(entity: E, component: Constructor<C>): C { return entity.get(component); } getComponentFromEntity(ab, BComponent) // 🟢 预期通过 getComponentFromEntity(ab, AComponent) // 🔴 预期报错 getComponentFromEntity(ab, CComponent) // 🔴 预期报错 //^? declare const a: Entity<BComponent | CComponent>; a.get(BComponent)// 🟢 预期通过 a.get(AComponent)// 🔴 预期报错
内容的提问来源于stack exchange,提问作者jon
相关产品推荐
相关产品推荐

