Typescript: Сериализация типов интерфейса для массива классов - PullRequest
0 голосов
/ 22 марта 2020

У меня проблема с машинописью.

В настоящее время я работаю над небольшим игровым движком, который использует модель сущность-компонент-система. Я хочу «сериализовать» типы интерфейса в массив классов (типы каждого свойства интерфейса), чтобы информировать систему о необходимых компонентах.

Что я хочу достичь в идеале:

export interface IMovable {
    position: CompPosition;
    velocity: CompVelocity;
}

export class MoveSystem extends System<IMovable> {

    // This array should have type, to ensure all components classes from IMovable are listed.
    protected requiredComponents = [ CompPosition, CompVelocity ];

    /// ...

}

Что я хочу сделать по крайней мере:

export interface IMovable {
    position: CompPosition;
    velocity: CompVelocity;
}

export class MoveSystem extends System<IMovable> {

    /* The properties of requiredComponents have the same name as in interface, but their types are 
       different - in interface, the type requires instances (which I want to keep this way in the 
       interface), but requiredComponents should contain classes. */
    protected requiredComponents = {
        position: CompPosition, 
        velocity: CompVelocity 
    };

    /// ...

}

Спасибо за каждое предложение.

Ответы [ 2 ]

0 голосов
/ 22 марта 2020

Я наконец нашел решение. Не самый лучший из возможных, но он работает так, как должен:

type Class<T> = new(...args: any[]) => T;

type ComponentStore<T> = { [P in keyof T]: Component };
type RequiredComponents<T extends ComponentStore<T>> = { [P in keyof T]: Class<T[P]> };

abstract class System<T extends ComponentStore<T>> {

    protected abstract requiredComponents: RequiredComponents<T>;

    // ...

}

interface IMovable {
    position: CompPosition;
    velocity: CompVelocity;
}

class MoveSystem extends System<IMovable> {

    protected requiredComponents = {
        position: CompPosition,
        velocity: CompVelocity
    };

    // ...

}

Но спасибо всем, кто пытался или даже читал.

0 голосов
/ 22 марта 2020

Так что это лучшее, что я могу придумать. Я не верю, что это возможно сделать (и если не эргономично с точки зрения разработчика) с подходом массива, поэтому я остановился на объектном.

class Position implements Component {
    x: number = 0
    y: number = 0
    readonly requiredComponents: {}
}

class Velocity implements Component {
    velX: number = 0
    velY: number = 0
    readonly requiredComponents: {}
}

type ComponentConstructor<T> = new(...args: any[]) => T

interface Component<A = {}, B = {}, C = {}, D = {}> {
    readonly requiredComponents: A & B & C & D
}

interface IMovable {
    position: ComponentConstructor<Position>
    velocity: ComponentConstructor<Velocity>
}

class Player implements Component<IMovable> {
    readonly requiredComponents = {
        position: Position,
        velocity: Velocity,
    }
}

С немного большим контекстом о том, как эти компоненты будут работать / взаимодействовать, я чувствую, что мог бы предложить лучшее решение - я не уверен, что то, что вы пытаетесь сделать, все еще необходимо.

...