如何编写配置对象的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
相关产品推荐
相关产品推荐

