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

TypeScript泛型映射类型为何推断交叉类型而非联合类型?

TypeScript泛型映射类型赋值时的交叉类型推断问题

问题场景

使用泛型映射类型TypeMap时,泛型类TestState的init方法中,为this.interfaceType赋值testObject时,TypeScript错误地将TypeMap[T]推断为InterfaceOne & InterfaceTwo(交叉类型),而非预期的InterfaceOne | InterfaceTwo(联合类型),触发类型错误。

最小复现代码:

interface InterfaceOne {
  fieldOne: string
}

interface InterfaceTwo {
  fieldTwo: string
}

enum Types {
  One = 'one',
  Two = 'two'
}

type TypeMap = {
  [Types.One]: InterfaceOne
  [Types.Two]: InterfaceTwo
}

export default class TestState<T extends Types> {
  private baseType: T
  private interfaceType: TypeMap[T] | null

  constructor(testFieldOne: T, testFieldTwo: TypeMap[T]) {
    this.baseType = testFieldOne
    this.interfaceType = testFieldTwo
  }

  private init(): void {
    if (this.baseType === Types.Two) {
      const testObject: InterfaceTwo = { fieldTwo: 'test' }
      console.log(this.interfaceType)
      this.interfaceType = testObject // ❌ 类型错误:Type 'InterfaceTwo' is not assignable to type 'TypeMap[T]'
    }
  }
}

问题原因

TypeScript无法通过类属性this.baseType的条件检查,自动缩小泛型参数T的范围。当检查this.baseType === Types.Two时,TypeScript仅能确定this.baseType的类型是Types.Two,但无法关联到泛型T也被限定为Types.Two。此时TypeMap[T]仍被视为依赖于整个T约束(Types.One | Types.Two)的泛型类型,TypeScript会要求赋值的类型满足TypeMap[T]的所有可能情况,即推断为InterfaceOne & InterfaceTwo交叉类型,导致InterfaceTwo无法匹配。

解决方案

方案1:类型断言匹配泛型类型

在赋值时,将testObject断言为当前泛型对应的TypeMap[T],明确告诉TypeScript该值符合泛型类型要求:

private init(): void {
  if (this.baseType === Types.Two) {
    const testObject: InterfaceTwo = { fieldTwo: 'test' }
    this.interfaceType = testObject as TypeMap[T]
  }
}

方案2:自定义类型守卫缩小类实例类型

定义类型守卫函数,将类实例的类型缩小为TestState<Types.Two>,让TypeScript自动推断interfaceType的类型为InterfaceTwo:

private isTypeTwo(): this is TestState<Types.Two> {
  return this.baseType === Types.Two
}

private init(): void {
  if (this.isTypeTwo()) {
    const testObject: InterfaceTwo = { fieldTwo: 'test' }
    this.interfaceType = testObject // ✅ 类型推断正确
  }
}

方案3:重构为判别式联合类型(推荐场景)

若无需保留泛型类结构,可将状态重构为判别式联合类型,利用TypeScript的自动类型缩小特性:

type TestState = 
  | { baseType: Types.One; interfaceType: InterfaceOne | null }
  | { baseType: Types.Two; interfaceType: InterfaceTwo | null }

function createTestState<T extends Types>(type: T, data: TypeMap[T]): TestState {
  return { baseType: type, interfaceType: data }
}

function init(state: TestState): void {
  if (state.baseType === Types.Two) {
    const testObject: InterfaceTwo = { fieldTwo: 'test' }
    state.interfaceType = testObject // ✅ 类型推断正确
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 22:34:54