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

如何让TypeScript正确理解泛型对象的赋值操作?

解决TypeScript泛型索引访问的类型兼容性问题(无需类型断言)

原代码与问题描述

type Type = 'one' | 'two' | 'three'

type TypeSelection = 'one' | 'two'

interface InnerObject<T extends Type> {
  name: string,
  type: T
}

type Obj<K extends Type> = {
  [P in K]?: InnerObject<P>
} & {
  [P in TypeSelection]: InnerObject<P>
}

const obj: Obj<Type> = {
  one: {
    name: 'a',
    type: 'one'
  },
  two: {
    name: 'a',
    type: 'two'
  }
}

function getInnerObject<T extends Type>(key: T) {
  const selectedObj: InnerObject<T> | undefined = obj[key]
  const defaultObj = obj['one']
}

这段代码中,我们期望obj[key]返回InnerObject<T> | undefined(因为T被约束为Type,key是T类型),但TypeScript会抛出如下错误:

Type 'InnerObject<"one"> | InnerObject<"two"> | InnerObject<"three"> | undefined' is not assignable to type 'InnerObject<T> | undefined'.
  Type 'InnerObject<"one">' is not assignable to type 'InnerObject<T>'.
    Type '"one"' is not assignable to type 'T'.
      '"one"' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype of constraint 'Type'.(2322)

问题根源在于原Obj<K>类型采用了两个映射类型的交叉,TypeScript无法将这种交叉类型的索引访问结果与泛型T建立精确对应关系,只能推断出所有可能类型的联合,进而认为联合类型中的某些成员无法赋值给InnerObject<T>。

解决方案:调整Obj类型定义为明确的映射结构

将Obj的类型定义改为单一的映射结构(或合并后的映射类型),让TypeScript能清晰识别每个key对应的value类型,从而正确推断泛型索引访问的结果:

type Type = 'one' | 'two' | 'three'
type TypeSelection = 'one' | 'two'

interface InnerObject<T extends Type> {
  name: string;
  type: T;
}

// 定义Obj类型:TypeSelection的属性必填,其余Type成员可选
type Obj = {
  [P in TypeSelection]: InnerObject<P>;
} & Partial<{ [P in Exclude<Type, TypeSelection>]: InnerObject<P>; }>;

// 或者更直观的写法(适合固定枚举值的场景):
// type Obj = {
//   one: InnerObject<'one'>;
//   two: InnerObject<'two'>;
//   three?: InnerObject<'three'>;
// };

const obj: Obj = {
  one: { name: 'a', type: 'one' },
  two: { name: 'a', type: 'two' }
};

function getInnerObject<T extends keyof Obj>(key: T) {
  // TypeScript能正确推断obj[key]的类型为Obj[T],无需额外断言
  const selectedObj = obj[key];
  const defaultObj = obj['one']; // 类型自动推断为InnerObject<'one'>
}

原理说明

调整后的Obj类型明确了每个key对应的value类型:

  • 对于TypeSelection中的'one'和'two',属性是必填的InnerObject<'one'>和InnerObject<'two'>
  • 对于Type中剩下的'three',属性是可选的InnerObject<'three'>

当函数使用T extends keyof Obj作为泛型约束时,TypeScript能准确将obj[key]的类型与T关联,自动推断出obj[key]的类型为Obj[T],完美匹配我们期望的InnerObject<T>(或InnerObject<T> | undefined),从而避免类型错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 00:20:11