I'm trying to accomplish a similar behavior that I can do with C#
. In C#
I can use reflection to dynamically instantiate a class based on the Type
class. The following code shows how to do in c#
, rather simple:
interface IHandler
{
void Handle();
}
var handlers = new Dictionary<string, Type>
{
{ "querydom", typeof(QueryDomHandler) },
{ "other", typeof(OtherHandler) },
};
var type = handlers["querydom"];
var instance = (IHandler)Activator.CreateInstance(type, args);
instance.Handle();
How can I accomplish the same with typescript
? I've sketched the following code, but I do not know how to get a "Type" from a class (QueryDomCommandHandler
), or how to instantiate a class dynamically without using its name ( new QueryDomCommandHandler()
).
let handlers = [];
handlers[CommandType.QueryDom] = QueryDomCommandHandler; //how to store the "type"?
chrome.runtime.onMessage.addListener((message: Command, sender, sendResponse) => {
logger.debug(`${isFrame ? 'Frame' : 'Window'} '${document.location.href}' received message of type '${CommandType[message.command]}'`);
const handlerType = handlers[CommandType.QueryDom];
const handlerInstance = ????? //how to instantiate the class?
if (message.command == CommandType.QueryDom) {
const handler = new QueryDomCommandHandler(message as RulesCommand);
const response = handler.handle();
sendResponse(response);
return true;
}
else if (message.command == CommandType.Highlight) {
const handler = new HighlightCommandHandler(message as RulesCommand);
handler.handle();
}
});
Any insights?
UPDATE
Thanks to the answers, here's my solution, although I would like to use the enum
instead of the hardcoded string in the Record
, but couldn't figure it out:
const handlers: Record<string, (new () => commands.CommandHandlerBase)> = {
'QueryDom': QueryDomCommandHandler,
'Highlight': HighlightCommandHandler,
'ClearHighlight': ClearHighlightCommandHandler,
};
const handlerType = handlers[commands.CommandType[message.command]];
const handler = new handlerType();
const response = await handler.handle(message);
It was so simple. You just need to use the Map
class instead of the Record
:
type WorkerHandlerConstructor = (new () => handlers.CommandHandlerBase);
handlers: Map<types.CommandType, WorkerHandlerConstructor> = new Map<types.CommandType, WorkerHandlerConstructor>([
[types.CommandType.Click, handlers.ClickCommandHandler],
[types.CommandType.Navigate, handlers.NavigateCommandHandler]
]);
And then
const handlerType = handlers.get(types.CommandType.Click);
const handler = new handlerType();