Skip to content
This repository has been archived by the owner on Jun 1, 2022. It is now read-only.

Improve Component types to allow for type inference on schema properties #263

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 15 additions & 10 deletions src/Component.d.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
import { PropType } from "./Types";

/**
* Base class for components.
*/

export type ComponentSchemaProp = {
default?: any;
type: PropType<any, any>;
Expand All @@ -13,18 +9,27 @@ export type ComponentSchema = {
[propName: string]: ComponentSchemaProp;
};

export class Component<C> {
static schema: ComponentSchema;
static isComponent: true;
constructor(props?: Partial<Omit<C, keyof Component<any>>> | false);
// Base class for components,
export declare class ComponentClass<C> {
copy(source: this): this;
clone(): this;
reset(): void;
dispose(): void;
constructor(props?: Partial<C> | false);
}

export interface ComponentConstructor<C extends Component<any>> {
export type ComponentInstance<C> = ComponentClass<C> & C;

interface ComponentStatic {
schema: ComponentSchema;
isComponent: true;
new (props?: Partial<Omit<C, keyof Component<any>>> | false): C;
new <C>(props?: Partial<C> | false): ComponentInstance<C>;
}

export interface ComponentConstructor<C> {
schema: ComponentSchema;
isComponent: true;
new (props?: Partial<C> | false): ComponentInstance<C>;
}

export declare const Component: ComponentStatic;
58 changes: 27 additions & 31 deletions src/Entity.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { Component, ComponentConstructor } from "./Component";
import {
ComponentConstructor,
ComponentInstance,
ComponentClass,
} from "./Component";

/**
* An entity in the world.
Expand All @@ -19,57 +23,57 @@ export class Entity {
* @param Component Type of component to get
* @param includeRemoved Whether a component that is staled to be removed should be also considered
*/
getComponent<C extends Component<any>>(
getComponent<C>(
Component: ComponentConstructor<C>,
includeRemoved?: boolean
): Readonly<C> | undefined;
): Readonly<ComponentInstance<C>> | undefined;

/**
* Get a component that is slated to be removed from this entity.
*/
getRemovedComponent<C extends Component<any>>(
Component: ComponentConstructor<C>
): Readonly<C> | undefined;
getRemovedComponent<C>(
Component: ComponentConstructor<C>
): Readonly<ComponentInstance<C>> | undefined;

/**
* Get an object containing all the components on this entity, where the object keys are the component types.
*/
getComponents(): { [componentName: string]: Component<any> };
getComponents(): { [componentName: string]: ComponentInstance<any> };

/**
* Get an object containing all the components that are slated to be removed from this entity, where the object keys are the component types.
*/
getComponentsToRemove(): { [componentName: string]: Component<any> };
getComponentsToRemove(): { [componentName: string]: ComponentInstance<any> };

/**
* Get a list of component types that have been added to this entity.
*/
getComponentTypes(): Array<Component<any>>;
getComponentTypes(): Array<ComponentConstructor<any>>;

/**
* Get a mutable reference to a component on this entity.
* @param Component Type of component to get
*/
getMutableComponent<C extends Component<any>>(
getMutableComponent<C extends any>(
Component: ComponentConstructor<C>
): C | undefined;
): ComponentInstance<C> | undefined;

/**
* Add a component to the entity.
* @param Component Type of component to add to this entity
* @param values Optional values to replace the default attributes on the component
*/
addComponent<C extends Component<any>>(
addComponent<C extends any>(
Component: ComponentConstructor<C>,
values?: Partial<Omit<C, keyof Component<any>>>
values?: Partial<Omit<C, keyof ComponentClass<C>>>
): this;

/**
* Remove a component from the entity.
* @param Component Type of component to remove from this entity
* @param forceImmediate Whether a component should be removed immediately
*/
removeComponent<C extends Component<any>>(
removeComponent<C extends any>(
Component: ComponentConstructor<C>,
forceImmediate?: boolean
): this;
Expand All @@ -79,7 +83,7 @@ export class Entity {
* @param Component Type of component
* @param includeRemoved Whether a component that is staled to be removed should be also considered
*/
hasComponent<C extends Component<any>>(
hasComponent<C extends any>(
Component: ComponentConstructor<C>,
includeRemoved?: boolean
): boolean;
Expand All @@ -88,45 +92,37 @@ export class Entity {
* Check if the entity has a component that is slated to be removed.
* @param Component Type of component
*/
hasRemovedComponent<C extends Component<any>>(
hasRemovedComponent<C extends any>(
Component: ComponentConstructor<C>
): boolean;

/**
* Check if the entity has all components in a list.
* @param Components Component types to check
*/
hasAllComponents(
Components: Array<ComponentConstructor<any>>
): boolean
hasAllComponents(Components: Array<ComponentConstructor<any>>): boolean;

/**
* Check if the entity has any of the components in a list.
* @param Components Component types to check
*/
hasAnyComponents(
Components: Array<ComponentConstructor<any>>
): boolean
hasAnyComponents(Components: Array<ComponentConstructor<any>>): boolean;

/**
* Remove all components on this entity.
* @param forceImmediate Whether all components should be removed immediately
*/
removeAllComponents(
forceImmediate?: boolean
): void
removeAllComponents(forceImmediate?: boolean): void;

copy(source: this): this
copy(source: this): this;

clone(): this
clone(): this;

reset(): void
reset(): void;

/**
* Remove this entity from the world.
* @param forceImmediate Whether this entity should be removed immediately
*/
remove(
forceImmediate?: boolean
): void;
remove(forceImmediate?: boolean): void;
}
40 changes: 21 additions & 19 deletions src/System.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {Component, ComponentConstructor} from "./Component";
import { ComponentConstructor } from "./Component";
import { Entity } from "./Entity";
import { World } from "./World";

Expand All @@ -9,13 +9,13 @@ interface Attributes {

export interface SystemQueries {
[queryName: string]: {
components: (ComponentConstructor<any> | NotComponent<any>)[],
components: (ComponentConstructor<any> | NotComponent<any>)[];
listen?: {
added?: boolean,
removed?: boolean,
changed?: boolean | ComponentConstructor<any>[],
},
}
added?: boolean;
removed?: boolean;
changed?: boolean | ComponentConstructor<any>[];
};
};
}

/**
Expand All @@ -38,12 +38,12 @@ export abstract class System<EntityType extends Entity = Entity> {
*/
queries: {
[queryName: string]: {
results: EntityType[],
added?: EntityType[],
removed?: EntityType[],
changed?: EntityType[],
}
}
results: EntityType[];
added?: EntityType[];
removed?: EntityType[];
changed?: EntityType[];
};
};

world: World<EntityType>;

Expand All @@ -60,7 +60,7 @@ export abstract class System<EntityType extends Entity = Entity> {
/**
* Called when the system is added to the world.
*/
init(attributes?: Attributes): void
init(attributes?: Attributes): void;

/**
* Resume execution of this system.
Expand All @@ -83,16 +83,18 @@ export abstract class System<EntityType extends Entity = Entity> {

export interface SystemConstructor<T extends System> {
isSystem: true;
queries: SystemQueries
queries: SystemQueries;
new (...args: any): T;
}

export interface NotComponent<C extends Component<any>> {
type: "not",
Component: ComponentConstructor<C>
export interface NotComponent<C extends any> {
type: "not";
Component: ComponentConstructor<C>;
}

/**
* Use the Not class to negate a component query.
*/
export function Not<C extends Component<any>>(Component: ComponentConstructor<C>): NotComponent<C>;
export function Not<C extends any>(
Component: ComponentConstructor<C>
): NotComponent<C>;
11 changes: 6 additions & 5 deletions src/SystemStateComponent.d.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { Component, ComponentConstructor } from "./Component";
import { ComponentConstructor, ComponentStatic } from "./Component";

/**
* Components that extend the SystemStateComponent are not removed when an entity is deleted.
*/
export class SystemStateComponent<C> extends Component<C> {
static isSystemStateComponent: true;
interface SystemStateComponentStatic extends ComponentStatic {
isSystemStateComponent: true;
}

export interface SystemStateComponentConstructor<C extends Component<any>> extends ComponentConstructor<C> {
export interface SystemStateComponentConstructor<C>
extends ComponentConstructor<C> {
isSystemStateComponent: true;
new (): C;
}

export declare const SystemStateComponent: SystemStateComponentStatic;
16 changes: 11 additions & 5 deletions src/TagComponent.d.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import { Component, ComponentConstructor } from "./Component";
import {
ComponentConstructor,
ComponentInstance,
ComponentStatic,
} from "./Component";

/**
* Create components that extend TagComponent in order to take advantage of performance optimizations for components
* that do not store data
*/
export class TagComponent extends Component<{}> {
static isTagComponent: true;
interface TagComponentStatic extends ComponentStatic {
isTagComponent: true;
new (): ComponentInstance<{}>;
}

export interface TagComponentConstructor<C extends Component<{}>> extends ComponentConstructor<C> {
export interface TagComponentConstructor extends ComponentConstructor<{}> {
isTagComponent: true;
new (): C;
}

export declare const TagComponent: TagComponentStatic;
19 changes: 11 additions & 8 deletions src/World.d.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Component, ComponentConstructor } from "./Component";
import { ComponentConstructor } from "./Component";
import { System, SystemConstructor } from "./System";
import { Entity } from "./Entity";
import { ObjectPool } from "./ObjectPool";
Expand All @@ -12,7 +12,6 @@ export interface WorldOptions {
* The World is the root of the ECS.
*/
export class World<EntityType extends Entity = Entity> {

/**
* Whether the world tick should execute.
*/
Expand All @@ -27,13 +26,18 @@ export class World<EntityType extends Entity = Entity> {
* Register a component.
* @param Component Type of component to register
*/
registerComponent<C extends Component<any>>(Component: ComponentConstructor<C>, objectPool?: ObjectPool<C> | false): this;
registerComponent<C extends any>(
Component: ComponentConstructor<C>,
objectPool?: ObjectPool<C> | false
): this;

/**
* Evluate whether a component has been registered to this world or not.
* @param Component Type of component to to evaluate
*/
hasRegisteredComponent<C extends Component<any>>(Component: ComponentConstructor<C>): boolean;
hasRegisteredComponent<C extends any>(
Component: ComponentConstructor<C>
): boolean;

/**
* Register a system.
Expand Down Expand Up @@ -68,16 +72,15 @@ export class World<EntityType extends Entity = Entity> {
/**
* Resume execution of this world.
*/
play(): void
play(): void;

/**
* Stop execution of this world.
*/
stop(): void
stop(): void;

/**
* Create a new entity
*/
createEntity(name?: string): EntityType

createEntity(name?: string): EntityType;
}
Loading