如何使用泛型缩小TypeScript联合类型的范围

如何使用泛型缩小TypeScript联合类型的范围,typescript,typescript-generics,union-types,Typescript,Typescript Generics,Union Types,我有一个更新状态的泛型函数(用例在React中动态处理表的更新),并使用泛型来确保调用该函数是类型安全的,但我不理解为什么TypeScript不会编译 在函数本身中,似乎Typescript没有使用所有可用信息来缩小类型范围,而是认为我仍在使用完整的联合。 它清楚地知道关于参数的足够多的信息来判断函数是否被正确调用,那么为什么它在检查实际实现的类型时失败了呢 在行[字段]=值时失败 最小示例: type First={a:string;b:string;c:string} 键入Second={b

我有一个更新状态的泛型函数(用例在React中动态处理表的更新),并使用泛型来确保调用该函数是类型安全的,但我不理解为什么TypeScript不会编译

在函数本身中,似乎Typescript没有使用所有可用信息来缩小类型范围,而是认为我仍在使用完整的联合。 它清楚地知道关于参数的足够多的信息来判断函数是否被正确调用,那么为什么它在检查实际实现的类型时失败了呢

行[字段]=值时失败

最小示例:

type First={a:string;b:string;c:string}
键入Second={b:string;c:string;d:string}
类型Third={c:string;d:string;e:string}
类型状态={
第一:第一[]
第二:第二[]
第三:第三[]
}
常数更新=<
它扩展了国家,
作为国家的一部分,
T扩展S[TK],
R扩展T[number],
F扩展了R的键
>(
州:州,,
标记名:TK,
行索引:编号,
字段:F,
数值:R[F]
) => {
//好的
常量标记=状态[标记名]
//好的
常量行=标记[rowIndex]
//行的typeof现在为“c”
//类型错误
行[字段]=值
}
常量状态:状态={
第一:[{a:,b:,c::}],
第二个:[{b:,c:,d::}],
第三:[{c:,d:,e::}],
}
//这正如预期的那样成功
更新(状态为“第一”,0,“a”,“新”)
//但这并没有达到预期的效果
//@ts预期错误
更新(状态为“第二”,0,“a”,“新”)
试试这个:

const update = <
  TK extends keyof State,
  F extends keyof State[TK][number]
>(
  state: State,
  tagName: TK,
  rowIndex: number,
  field: F,
  value: State[TK][number][F]
) => {
  // fine
  const tag = state[tagName]

  // fine
  // The type annotation here is required
  // (otherwise the type is inferred as First | Second | Third)
  const row: State[TK][number] = tag[rowIndex]

  // now also fine
  row[field] = value
}
const更新=<
作为国家的一部分,
F国家元首[TK][人数]
>(
州:州,,
标记名:TK,
行索引:编号,
字段:F,
值:状态[TK][number][F]
) => {
//好的
常量标记=状态[标记名]
//好的
//此处的类型注释是必需的
//(否则类型推断为第一|第二|第三)
常量行:状态[TK][number]=标记[rowIndex]
//现在也可以了
行[字段]=值
}

谢谢,效果很好。请注意,这需要两个阶段的
常量行:…
部分,并将F的类型更改为不仅仅是
keyof R
。不知道为什么TS不能解决这个问题,但请记住这一点