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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 11:27:03