Problem
Error: Property 'attach' does not exist on type 'Component'.
How can I return an arbitrary subclass stored in a custom dictionary type, and use a method that only exists on the subclass if the dictionary type has a return value of the superclass?
Context
I have a Component class that has many subclasses.
My GameActor class can have Components attached to it. An attached component is stored in the ComponentContainer member which is a custom type, and can be any of the subclasses of Component. E.g. MovementComponent, HealthComponent, EventComponent, etc. can all be stored in ComponentContainer.
When I retrieve an attached Component, I get the "Property does not exist" error above when I try and call a method from the retrieved Component. If I open up the browser's dev tools, I can see my log of the returned type looks like it is, in fact, the subclass type
ComponentContainer type definition
//globals.d.ts
// ComponentContainer type definition
// populated data structure will look like:
// {
// "EventComponent": EventComponent,
// "MovementComponent": MovementComponent,
// "FooComponent": FooComponent
// // etc...
// }
type ComponentContainer = {
[componentName: string]: Component;
}
The GameActor has a bunch of methods to add, remove, get, and list the attached components.
//GameActor class that can have Components attached to it
export abstract class GameActor extends GameObject implements IGameActor {
protected components: ComponentContainer;
constructor() {
this.components = {};
}
public getComponent(key: string): Component|null {
return this.components[key];
}
}
// Player subclass of GameActor
export class Player extends GameActor implements IPlayer {
//Player class code here...
}
//Component superclass
export abstract class Component {
protected typeId: string;
public getTypeId(): string {
return this.typeId;
}
}
//EventComponent subclass
export class EventComponent extends Component implements IEventComponent {
public attach(event: Event|CustomEvent): void {
//Attach code here...
}
}
Now somewhere else in the code I want to do the following:
this.getComponent("EventComponent").attach(PlayerDeathEvent.create(this));
at which point I receive the error. If I log out the following code, it appears both are of type EventComponent.
let ec = this.Player.getComponent("EventComponent");
let t = new EventComponent();

I expect .attach to not throw an error because the compiler knows the component is of type EventComponent.