UPDATE:: reproducible link to the TypeScript playground
I have also found a solution in the provided link, but I am still open to learning why my initial approach didn't work.
TLDR;
This method does not yield the expected results
getEntitiesByComponent<T extends Component<any>>(compType: new (...args: any[]) => T | Array<new (...args: any[]) => T>): IEntity[] {
However, this alternative does work
getEntitiesByComponent<T extends new (...args: any[]) => Component<any>>(compType: T | Array<T>): IEntity[]
UPDATE 2
Code snippet from the reproducible link
export interface IComponent {
setEntity: (value: IEntity) => void;
getEntity: () => IEntity;
}
export interface IEntity {
components: any[];
}
export const entitySet = new Set<IEntity>();
export class Component<T extends object> implements IComponent {
private _entity: IEntity | undefined;
setEntity(value: IEntity) {
if (this._entity === value) {
return;
}
this._entity = value;
}
getEntity(): IEntity {
return this._entity!;
}
props: T;
constructor(props?: T) {
this.props = {
...props as T
}
}
}
export class ViewComponent extends Component<any> {
constructor(props: any) {
super(props);
}
}
export class TransformComponent extends Component<any> {
constructor(props?: any) {
super();
}
}
// Typing issue here
function getEntitiesByComponent<T extends Component<any>>(compType: new (...args: any[]) => T | Array<new (...args: any[]) => T>): IEntity[] {
const compTypes = Array.isArray(compType) ? compType : [compType];
return Array.from(entitySet.values())
.filter(e => {
return e.components.some(c => compTypes.some(compType => c instanceof compType))
});
}
// This works fine
function getEntitiesByComponentThatWorks<T extends new (...args: any[]) => Component<any>>(compType: T | Array<T>): IEntity[] {
const compTypes = Array.isArray(compType) ? compType : [compType];
return Array.from(entitySet.values())
.filter(e => e.components.some(c => compTypes.some(compType => c instanceof compType)))
}
// error
const viewComponentEntities = getEntitiesByComponent([ViewComponent, TransformComponent]);
// no error
const viewComponentEntitiesWorks = getEntitiesByComponentThatWorks([ViewComponent, TransformComponent]);
ORIGINAL POST
I am attempting to create a function that can accept either a single instance or an array of instances of objects that inherit from a common parent class.
// EntityManager.ts
/**
* Function designed to receive either a single instance of a constructor returning a
* Component<any> or an array of similar and should deliver entities containing a
* component based on the input instances.
**/
getEntitiesByComponent<T extends Component<any>>(compType: new (...args: any[]) => T | Array<new (...args: any[]) => T>): IEntity[] {
const compTypes = Array.isArray(compType) ? compType : [compType];
return Array.from(this._entitySet.values())
.filter(e => {
return e.components.some(c => compTypes.some(compType => c instanceof compType))
});
}
The classes ViewComponent and TransformComponent are both extensions of Component.
// ViewComponent.ts
import { Component } from '../components/component';
export type ViewComponentProps = {
alias: string;
src: string;
}
export class ViewComponent extends Component<ViewComponentProps> {
constructor(props: ViewComponentProps) {
super(props);
}
}
// TransformComponent.ts
import { Component } from './component';
export type TransformComponentProps = {
x: number;
y: number;
scaleX?: number;
scaleY?: number;
zIndex?: number;
}
export class TransformComponent extends Component<TransformComponentProps> {
private static _defaultProps: TransformComponentProps = {
x: 0,
y: 0,
scaleX: 1,
scaleY: 1,
zIndex: 0,
};
constructor(props?: TransformComponentProps) {
super({
...TransformComponent._defaultProps,
...props
});
}
}
When I call the function like this
const viewComponentEntities = EntityManager.getInstance().getEntitiesByComponent([ViewComponent, TransformComponent]);
TypeScript throws the following error
TS2345: Argument of type
(typeof TransformComponent | typeof ViewComponent)[]
is not assignable to parameter of type
new (...args: any[]) => Component<any> | (new (...args: any[]) => Component<any>)[]
Type
(typeof TransformComponent | typeof ViewComponent)[]
does not match the signature
new (...args: any[]): Component<any> | (new (...args: any[]) => Component<any>)[]
I am unsure why this error is occurring and how to resolve it.