I'm searching for a way to get a list of all classes implementing a certain interface in Typescript.
In .Net for example, you can do this using reflection but i cant find any information about doing the same thing in Typescript.
Code example of what i want to do:
interface IControlPanel { }
class BasicControlPanel implements IControlPanel { }
class AdvancedControlPanel implements IControlPanel { }
window.onload = () =>
{
var controlPanels = IControlPanel.GetImplementations();
for (var x = 0; x < controlPanels.length; x++)
{
document.write(controlPanels[x] + ", "); //outputs: BasicControlPanel, AdvancedControlPanel,
}
};
Even better would ofcourse be if the classes are easy to instantiate.
As I mentioned in the comments, it's a stated non-goal of TypeScript (see non-goal #5) to emit JavaScript that is dependent on the type system, so there will be nothing at runtime you can use automatically to do what you want.
You can, of course, use TypeScript to help you maintain a registry of types that can be used almost exactly how you want. I'd suggest using class decorators, like so:
interface IControlPanel {
// add some methods or something to distinguish from {}
doAThing(): void;
}
// add a registry of the type you expect
namespace IControlPanel {
type Constructor<T> = {
new(...args: any[]): T;
readonly prototype: T;
}
const implementations: Constructor<IControlPanel>[] = [];
export function GetImplementations(): Constructor<IControlPanel>[] {
return implementations;
}
export function register<T extends Constructor<IControlPanel>>(ctor: T) {
implementations.push(ctor);
return ctor;
}
}
Now, instead of declaring that the class implements IControlPanel
, you use @IControlPanel.register
:
@IControlPanel.register
class BasicControlPanel {
doAThing() { }
}
@IControlPanel.register
class AdvancedControlPanel {
doAThing() { }
}
If you try to register a class that does not implement IControlPanel
, you will get an error:
// error, doAThing is missing from BadControlPanel
@IControlPanel.register
class BadControlPanel {
doNothing() { }
}
Now you can use the registry the way you want, mostly:
window.onload = () => {
var controlPanels = IControlPanel.GetImplementations();
for (var x = 0; x < controlPanels.length; x++) {
document.write(controlPanels[x].name + ", ");
const panel = new controlPanels[x]();
panel.doAThing();
}
};
I say "mostly" because I've stored constructors, not strings, since you wanted a way to instantiate them. You can get the name
property of the constructor for the string. And you can instantiate the classes, assuming they all take the same constructor argument types.
Hope that helps; good luck!
Stackblitz example
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With