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

映射到对象时TypeScript映射类型失效问题排查

问题:为何DependencyRegistry的注册逻辑会抛出TypeScript错误?

我定义了描述Dependencies与Container的类型,希望为每个依赖注册对应的提供者函数。以下代码实现了两种“注册表”:

  • DependencyProviders:依赖名称与其提供者的映射
  • DependencyRegistry:依赖名称与包含其提供者的对象的映射

代码实现如下:

interface Dependencies {
  a: string
  b: number
  c: boolean
}

type DependencyProviders = {
  [DepName in keyof Dependencies]: () => Dependencies[DepName]
}

type DependencyRegistry = {
  [DepName in keyof Dependencies]: {
    provider: () => Dependencies[DepName]
  }
}

class Container {
  private readonly providers: Partial<DependencyProviders> = {}
  private readonly registry: Partial<DependencyRegistry> = {}

  register<DepName extends keyof Dependencies>(
    name: DepName,
    provider: DependencyProviders[DepName]
  ) {
    this.providers[name] = provider
    this.registry[name] = { provider } // 此行抛出错误
  }
}

该行代码抛出的错误信息:

Type '{ provider: DependencyProviders[DepName]; }' is not assignable to type 'Partial<DependencyRegistry>[DepName]'.
  Type '{ provider: DependencyProviders[DepName]; }' is not assignable to type '{ provider: () => string; } & { provider: () => number; } & { provider: () => boolean; }'.
    Type '{ provider: DependencyProviders[DepName]; }' is not assignable to type '{ provider: () => string; }'.
      Types of property 'provider' are incompatible.
        Type 'DependencyProviders[DepName]' is not assignable to type '() => string'.
          Type '(() => string) | (() => number) | (() => boolean)' is not assignable to type '() => string'.
            Type '() => number' is not assignable to type '() => string'.
              Type 'number' is not assignable to type 'string'.
                Type '() => Dependencies[DepName]' is not assignable to type '() => string'.
                  Type 'Dependencies[DepName]' is not assignable to type 'string'.
                    Type 'string | number | boolean' is not assignable to type 'string'.
                      Type 'number' is not assignable to type 'string'.

原因分析

TypeScript的类型推断在这里出现了窄化失败:

  1. 对于DependencyProviders,直接赋值this.providers[name] = provider可以正常工作,因为DependencyProviders[DepName]和Partial<DependencyProviders>[DepName]是精确匹配的——泛型DepName会严格约束提供者类型与依赖名称的对应关系。
  2. 但对于DependencyRegistry,创建{ provider }时,TypeScript无法将DepName的泛型约束传递到这个对象的类型推断中,反而将其泛化为{ provider: DependencyProviders[keyof Dependencies] }(即提供者可能是任意类型的函数)。而Partial<DependencyRegistry>[DepName]要求的是与当前依赖完全匹配的提供者对象,因此TypeScript判定泛化后的对象无法满足类型要求,抛出不兼容错误。

修复方案

有两种可靠的修复方式:

方式一:显式类型断言

直接告知TypeScript,{ provider }就是当前DepName对应的注册表项类型:

this.registry[name] = { provider } as DependencyRegistry[DepName]

方式二:用辅助函数约束类型

通过一个辅助函数来生成符合要求的注册表项,利用函数参数的泛型约束让TypeScript正确推断类型:

private createRegistryEntry<DepName extends keyof Dependencies>(
  provider: DependencyProviders[DepName]
): DependencyRegistry[DepName] {
  return { provider }
}

// 在register方法中调用
this.registry[name] = this.createRegistryEntry(provider)

修复后的完整代码(方式二示例)

interface Dependencies {
  a: string
  b: number
  c: boolean
}

type DependencyProviders = {
  [DepName in keyof Dependencies]: () => Dependencies[DepName]
}

type DependencyRegistry = {
  [DepName in keyof Dependencies]: {
    provider: () => Dependencies[DepName]
  }
}

class Container {
  private readonly providers: Partial<DependencyProviders> = {}
  private readonly registry: Partial<DependencyRegistry> = {}

  private createRegistryEntry<DepName extends keyof Dependencies>(
    provider: DependencyProviders[DepName]
  ): DependencyRegistry[DepName] {
    return { provider }
  }

  register<DepName extends keyof Dependencies>(
    name: DepName,
    provider: DependencyProviders[DepName]
  ) {
    this.providers[name] = provider
    this.registry[name] = this.createRegistryEntry(provider)
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 08:00:30