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

如何编写配置对象的TypeScript泛型 支持属性函数引用其他属性返回值

完整实现方案

前置类型定义

首先补全Locator和注册表相关的基础类型:

class Locator<T = Record<string, unknown>> {
  get<K extends keyof T>(serviceName: K): T[K] {
    return this.services[serviceName];
  }
  constructor(private services: T) {}
}

// 定义单个注册表项的工厂函数类型
type RegistryFactory<Services, Config, R> = (args: {
  config: Config;
  servicelocatorImpl: Locator<Services>;
}) => R;

// 注册表配置整体类型约束
type RegistryConfig<Services, Config = unknown> = {
  [K in keyof Services]: [RegistryFactory<Services, Config, Services[K]>]
};

核心函数定义

利用TS的泛型推断特性,无需手动传入泛型参数,TS会自动从传入的配置推导服务类型:

// 支持传入外部Config类型,默认是unknown
function defineServiceRegistryItems<Services, Config = unknown>(
  registryConfig: RegistryConfig<Services, Config>
) {
  // 可在此处补充运行时初始化逻辑:遍历配置初始化所有服务、生成Locator实例等
  // 按需求返回原配置,也可以返回初始化后的Locator实例
  return registryConfig;
}

使用示例

和预期用法完全一致,自动获得完整类型安全:

const r = defineServiceRegistryItems({
  greeting: [() => 'Hello World'],
  sayHelloWorld: [({ servicelocatorImpl }) => {
    // 自动推断get('greeting')返回string类型,输入错误服务名会直接报类型错误
    const greeting = servicelocatorImpl.get('greeting');
    return `${greeting}! This is from sayHelloWorld`;
  }],
  getUser: [() => ({ id: 1, name: 'test' })]
});

// 调用时也能自动获得类型提示,返回值类型会被正确推导

关键优化说明

  • 移除了原定义中的Exclude<keyof T, Prop>约束,类型层面不需要限制属性访问,运行时只要保证服务初始化顺序即可满足「引用已定义服务」的要求
  • 泛型Services直接映射为所有服务的返回值集合,无需额外递归推导类型,避免了循环类型报错
  • 支持自定义外部Config类型,如果工厂函数需要用到全局配置,可以显式传入Config泛型参数:
    type AppConfig = { baseUrl: string };
    const r = defineServiceRegistryItems<{}, AppConfig>({
      // 此处args.config会自动推断为AppConfig类型
      getBaseUrl: [({ config }) => config.baseUrl]
    })
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 01:36:02