You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在TypeScript中存储类型并实现动态实例化?

TypeScript实现类似C#的反射动态实例化类

问题描述

想要在TypeScript中实现类似C#通过反射基于Type类动态实例化类的功能,以下是C#的实现示例:

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();

尝试编写TypeScript代码草稿时,遇到两个问题:不知道如何存储类的“类型引用”,也不清楚如何不直接使用类名动态实例化类:

let handlers = [];
handlers[CommandType.QueryDom] = QueryDomCommandHandler; // 如何存储"类型"?

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 = ????? // 如何实例化类?
    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();
    }
});

更新:已实现基础方案,但希望用Enum替代Record中的硬编码字符串,尚未找到方法:

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);

解决方案

1. 基础实现:存储类引用并动态实例化

在TypeScript中,类本身就是可直接存储的构造函数引用,无需像C#那样通过typeof获取类型。可通过Record类型定义存储结构,明确构造函数的类型约束:

步骤1:统一基类与构造函数签名

确保所有处理器类继承自同一基类(如CommandHandlerBase),并保持构造函数签名一致:

// 基类定义
abstract class CommandHandlerBase {
  abstract handle(message: Command): Promise<any> | void;
}

// 示例处理器类
class QueryDomCommandHandler extends CommandHandlerBase {
  constructor(private message: RulesCommand) {
    super();
  }
  async handle() {
    // 业务逻辑实现
  }
}

步骤2:定义处理器映射

用Record构建枚举与处理器类的映射,键为CommandType枚举值,值为对应类的构造函数:

enum CommandType {
  QueryDom,
  Highlight,
  ClearHighlight
}

const handlers: Record<CommandType, new (message: RulesCommand) => CommandHandlerBase> = {
  [CommandType.QueryDom]: QueryDomCommandHandler,
  [CommandType.Highlight]: HighlightCommandHandler,
  [CommandType.ClearHighlight]: ClearHighlightCommandHandler
};

步骤3:动态实例化与调用

在消息监听逻辑中,通过枚举值获取构造函数,实例化后调用处理方法:

chrome.runtime.onMessage.addListener(async (message: Command, sender, sendResponse) => {
    logger.debug(`${isFrame ? 'Frame' : 'Window'} '${document.location.href}' received message of type '${CommandType[message.command]}'`);
 
    const handlerType = handlers[message.command];
    // 处理无对应处理器的边界情况
    if (!handlerType) {
      logger.error(`No handler registered for command: ${CommandType[message.command]}`);
      return;
    }
    
    const handler = new handlerType(message as RulesCommand);
    const response = await handler.handle();
    sendResponse(response);
    return true;
});

2. 进阶:用Enum替代硬编码字符串

若CommandType定义为字符串值枚举,可直接将其作为Record的键类型,彻底消除硬编码字符串:

步骤1:定义字符串值Enum

enum CommandType {
  QueryDom = 'QueryDom',
  Highlight = 'Highlight',
  ClearHighlight = 'ClearHighlight'
}

步骤2:更新处理器映射

直接使用Enum成员作为键,无需硬编码字符串:

const handlers: Record<CommandType, new () => commands.CommandHandlerBase> = {
  [CommandType.QueryDom]: QueryDomCommandHandler,
  [CommandType.Highlight]: HighlightCommandHandler,
  [CommandType.ClearHighlight]: ClearHighlightCommandHandler
};

步骤3:简化获取逻辑

由于message.command本身为CommandType类型,直接用其作为键即可:

const handlerType = handlers[message.command];
// 后续实例化与调用逻辑同上

这样既保证类型安全,又完全替代硬编码字符串,满足需求。


内容的提问来源于stack exchange,提问作者JobaDiniz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 21:59:54