我目前正在探索一种方法的替代方法,该方法以前有效,但在JavaScript中具有一些复杂性,我希望避免这种方法.
所以,我重新考虑了一下打字层,我想出了一个非常接近我想要的东西.
唯一的问题是,我有一个错误,我无法摆脱without using ts-ignore.
有人知道我怎样才能在不 destruct 以下设计的情况下解决这个问题吗?
- 我想避免实现和代码重复,所以TypeScrip需要从but I can afford some ts hack and complexity in the abstractions classes的JavaScript层推断类型
- 在js:
(System* => _SystemGameMiddle => SystemGameMiddle => _System => System)
中,原型需要如下所示 - 我可以在
SystemGameMiddle
或System
中添加类型复杂性,但不能在System*
中添加 -
system.test
应公开注入到类类型的所有组件.
type Constructor<T> = new ( ...args: never ) => T;
type ComponentType<T extends Component=Component> = Constructor<T>
// components
abstract class Component {}
class ComponentA extends Component { #id = Symbol() }
class ComponentB extends Component { #id = Symbol() }
class ComponentC extends Component { #id = Symbol() }
// systems
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;
}
}
//🔴 try adding any "middleware" class between System and final systemA
//// @ts-ignore - this is not really a solution to use @ts-ignore
abstract class SystemGameMiddle<R extends ComponentType[]=ComponentType[]> extends System.config(
[ComponentA] // this middleware will intercept constructor to also add and make avaible ComponentA
)<R> {
static override config<
const R extends ComponentType[],
>(
config: R
) {
abstract class _SystemGameMiddle<RR extends ComponentType[]=R> extends this<RR|R> {}
// this will work for ts side, but add complexity on js side because need add static field to keep track of the original config and we also lost the extends of SystemGameMiddle
// abstract class _SystemGameMiddle<RR extends ComponentType[]=R> extends super.config( config )<RR|R> {}
return _SystemGameMiddle;
}
override update() {
this.test1;
this.test2;
this.test3();
}
}
// for the hight level, i hould not have typescript complexity, ts should be almost automaticly deduce the type with ths js side injected in static class field
export class System1 extends SystemGameMiddle.config(
[ComponentB]
) {
}
export class System2 extends SystemGameMiddle.config(
[ComponentB, ComponentC]
) {
}
// TEST:::
// js: proto should be (System1 => _SystemGameMiddle => SystemGameMiddle => __System => System)
declare const system1:System1;
system1.test1; //ts: expected: [] | [typeof ComponentA] | [typeof ComponentB]
system1.test2; //ts: expected: typeof ComponentA | typeof ComponentB
system1.test3(); //ts: expected: typeof ComponentA | typeof ComponentB
// js: proto should be (System2 => _SystemGameMiddle => SystemGameMiddle => __System => System)
declare const system2:System2;
system2.test1; // ts: expected: [] | [typeof ComponentA] | [typeof ComponentB, typeof ComponentC]
system2.test2; //ts: expected: typeof ComponentA | typeof ComponentB | typeof ComponentC
system2.test3(); //ts: expected: typeof ComponentA | typeof ComponentB | typeof ComponentC
type SystemWith<
R extends ComponentType,
> = System & { test3<T extends R>( ): T}; // with implements
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 );