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

TypeScript中服务类实例Map存储的Service接口类型定义问题

TypeScript服务实例Map的类型约束解决方案

你当前的Service接口定义存在问题:实例对象本身并没有prototype属性,prototype是构造函数的专属属性,实例的constructor才指向对应的构造函数。下面是修正后的类型约束和实现代码:

正确的类型定义与实现

首先,我们需要明确服务实例和构造函数的类型关联,确保类型检查有效:

// 约束所有服务实例必须包含合法的构造函数(带name属性)
type ServiceInstance = {
  constructor: { name: string };
};

// 存储服务实例的Map,明确值的类型为ServiceInstance
const servicesMap = new Map<string, ServiceInstance>();

/**
 * 从serviceMap返回已实例化的服务
 * @param serviceConstructor 服务的构造函数(推荐用构造函数作为标识)
 */
export function getService<T extends ServiceInstance>(serviceConstructor: new () => T): T {
  const serviceName = serviceConstructor.name;
  if (!servicesMap.has(serviceName)) {
    throw new Error(`error_services: ${serviceName} is not registered`);
  }

  return servicesMap.get(serviceName) as T;
}

/**
 * 将已实例化的服务保存到serviceMap
 * @param serviceInstance 服务的实例
 */
export function registerService<T extends ServiceInstance>(serviceInstance: T) {
  const serviceName = serviceInstance.constructor.name;
  if (servicesMap.has(serviceName)) {
    throw new Error(
      `error_services: ${serviceName} has already been registered and should be register only in services-provider.ts`
    );
  }

  servicesMap.set(serviceName, serviceInstance);
}

代码说明

  • ServiceInstance:统一约束所有服务实例的结构,确保实例能通过constructor.name获取唯一标识。
  • getService改为接收构造函数而非实例,更符合依赖注入的常规用法,同时通过泛型T让返回值类型与构造函数实例类型严格匹配,避免类型断言的滥用。
  • registerService直接接收服务实例,通过实例的构造函数名称作为Map的key,类型约束确保传入的参数是合法的服务实例。

使用示例

export class MyService implements ServiceInstance {
  constructor() {
    // 初始化逻辑
  }

  someMethod() {}
}

// 注册服务实例
const myService = new MyService();
registerService(myService);

// 通过构造函数获取服务(类型自动推断为MyService)
const retrievedService = getService(MyService);
retrievedService.someMethod(); // 类型检查正常通过

如果坚持要让getService接收实例作为参数,可调整为以下版本(不推荐,因为获取服务时用构造函数作为标识更合理):

export function getService<T extends ServiceInstance>(service: T): T {
  const serviceName = service.constructor.name;
  if (!servicesMap.has(serviceName)) {
    throw new Error(`error_services: ${serviceName} is not registered`);
  }

  return servicesMap.get(serviceName) as T;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 21:45:10