TypeScript无接口中间静态类类型错误解决方案咨询
解决TypeScript系统类继承中的类型错误问题
问题背景
正在替换原有JavaScript实现(原方案复杂度较高),调整TypeScript层实现后已接近预期,但SystemGameMiddle类继承时必须依赖@ts-ignore才能消除类型错误。需在满足以下约束的前提下解决该问题:
- 避免代码重复,TypeScript需从JavaScript层推断类型,允许在抽象类中使用TypeScript技巧与复杂度
- JavaScript原型链必须保持:
System* => _SystemGameMiddle => SystemGameMiddle => __System => System - 仅可在
SystemGameMiddle或System中增加类型复杂度,不可修改System*相关代码 system.test系列属性需暴露所有注入的组件类型
解决方案
通过类型断言明确System.config返回类的泛型兼容关系,替代@ts-ignore。修改后的完整代码如下:
type Constructor<T> = new ( ...args: never ) => T; type ComponentType<T extends Component=Component> = Constructor<T> // 组件 abstract class Component {} class ComponentA extends Component { #id = Symbol() } class ComponentB extends Component { #id = Symbol() } class ComponentC extends Component { #id = Symbol() } // 系统 abstract class System<R extends ComponentType[]=ComponentType[]> { static config< const R extends ComponentType[], >( config: R ) { abstract class __System<RR extends ComponentType[]=R> extends this<RR|R> {} return __System; } declare test1: R; declare test2: R[number]; declare test3: <T extends R[number]>() => T; public update() { this.test1; } } // ✅ 移除@ts-ignore,使用类型断言解决类型不匹配 abstract class SystemGameMiddle<R extends ComponentType[] = ComponentType[]> extends (System.config([ComponentA]) as new <RR extends ComponentType[]>() => System<[typeof ComponentA, ...RR]>)<R> { static override config<const R extends ComponentType[]>(config: R) { abstract class _SystemGameMiddle<RR extends ComponentType[] = R> extends this<RR | R> {} return _SystemGameMiddle; } override update() { this.test1; this.test2; this.test3(); } } // 高层代码 export class System1 extends SystemGameMiddle.config([ComponentB]) {} export class System2 extends SystemGameMiddle.config([ComponentB, ComponentC]) {} // 测试验证 declare const system1: System1; system1.test1; // 类型:[typeof ComponentA] | [typeof ComponentB] system1.test2; // 类型:typeof ComponentA | typeof ComponentB system1.test3(); // 类型:typeof ComponentA | typeof ComponentB declare const system2: System2; system2.test1; // 类型:[typeof ComponentA] | [typeof ComponentB, typeof ComponentC] system2.test2; // 类型:typeof ComponentA | typeof ComponentB | typeof ComponentC system2.test3(); // 类型:typeof ComponentA | typeof ComponentB | typeof ComponentC type SystemWith<R extends ComponentType> = System & { test3<T extends R>( ): T}; function useSystem1( system:System ) { system.test1; system.test3; } function useSystem2( system:SystemGameMiddle ) { system.test1; system.test3; } function useSystem3( system:SystemWith<typeof ComponentB> ) { system.test1; system.test3(); } useSystem1( system1 ); useSystem2( system1 ); useSystem3( system1 );
关键修改说明
- 类型断言适配泛型:将
System.config([ComponentA])断言为new <RR extends ComponentType[]>() => System<[typeof ComponentA, ...RR]>,明确该类接受泛型参数RR并自动合并ComponentA与RR的组件类型,解决了泛型不匹配导致的类型错误。 - 保留原有JS逻辑:未修改JavaScript层的原型链或实现逻辑,仅在TypeScript类型层面调整,完全符合原型链约束。
- 满足所有设计要求:
- 无代码重复,TypeScript仍从JS层注入的配置推断类型
- 仅修改了
SystemGameMiddle的类型逻辑,未触碰System* test1/test2/test3仍能正确暴露所有注入的组件类型
内容的提问来源于stack exchange,提问作者jon
相关产品推荐
相关产品推荐

