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

泛型场景下TypeScript提示Record无法索引的原因及修正方案

TypeScript泛型索引报错原因及解决方法

原问题代码

type Foo<K extends string, T extends Record<K, string>> = {
  keys: K
  value: T
}

function bar<T extends Foo<'1' | '2', { 1: 'a', 2: 'b' }>>(def: T['value'], key: T['keys']) {
  // Type 'T["keys"]' cannot be used to index type 'T["value"]'.(2536)
  return def[key];
}

报错原因

TypeScript的类型系统无法追踪T['keys']和T['value']之间的原始约束关联。当使用T extends Foo<'1' | '2', { 1: 'a', 2: 'b' }>时,TypeScript仅检查T的结构是否匹配Foo的实例类型,不会保留Foo泛型参数间的约束(即value必须是Record<keys, string>)。

这意味着TypeScript会认为存在这样的T:它结构上符合Foo的子类型要求,但T['keys']并非T['value']的有效索引(比如{ keys: '1', value: { 2: 'b' } },虽然它违反了Foo的原始泛型约束,但结构上属于Foo<'1' | '2', { 1: 'a', 2: 'b' }>的子类型),因此会抛出索引不合法的错误。

正确代码示例

方案1:直接关联索引键与值类型

通过泛型参数K直接绑定键类型和对应的值类型,让TypeScript明确两者的索引关系:

type Foo<K extends string, T extends Record<K, string>> = {
  keys: K
  value: T
}

function bar<K extends '1' | '2'>(def: Record<K, string>, key: K) {
  return def[key];
}

方案2:基于完整的Foo类型约束

如果需要保留Foo的结构传递,直接使用完整的Foo对象作为参数,TypeScript能正确识别内部属性的约束关系:

type Foo<K extends string, T extends Record<K, string>> = {
  keys: K
  value: T
}

function barFromFoo<K extends string, V extends Record<K, string>>(foo: Foo<K, V>) {
  return foo.value[foo.keys];
}

// 调用示例
const foo1: Foo<'1', { 1: 'a' }> = { keys: '1', value: { 1: 'a' } };
console.log(barFromFoo(foo1)); // 类型为'a'

const foo2: Foo<'1' | '2', { 1: 'a', 2: 'b' }> = { keys: '1' | '2', value: { 1: 'a', 2: 'b' } };
console.log(barFromFoo(foo2)); // 类型为'a' | 'b'

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 15:29:50