Typescript 如何正确键入更新对象指定字段值的函数

Typescript 如何正确键入更新对象指定字段值的函数,typescript,Typescript,我实现了一个函数,它接受对象、回调和包含该对象键的数组。此函数使用参数中提供的回调更新数组中指定的每个字段的值 例如: const foo = { a: 3, b: 4, c: 4 } const bar = updateFields(foo, (val) => val + 10, ['a', 'b']) console.log(bar) // { a: 13, b: 14, c: 4 } 现在我已经实现并测试了这个函数,所以它工作正常 const updateFields = <

我实现了一个函数,它接受对象、回调和包含该对象键的数组。此函数使用参数中提供的回调更新数组中指定的每个字段的值

例如:

const foo = { a: 3, b: 4, c: 4 }
const bar = updateFields(foo, (val) => val + 10, ['a', 'b'])

console.log(bar) // { a: 13, b: 14, c: 4 }
现在我已经实现并测试了这个函数,所以它工作正常

const updateFields = <T extends {}, K extends keyof T, V>(
  obj: T,
  callback: (val: T[K]) => V,
  fields: K[]
) =>
  Object.entries<T[K]>(obj).reduce(
    (acc, [key, value]) => {
      if (fields.includes(key as K)) {
        acc[key] = callback(value)
      } else {
        acc[key] = value
      }

      return acc
    },
    {} as any
  )
const updateFields=(
obj:T,
回调:(val:T[K])=>V,
字段:K[]
) =>
Object.entries(obj).reduce(
(acc,[键,值]=>{
if(字段包括(键为K)){
acc[键]=回调(值)
}否则{
acc[键]=值
}
返回acc
},
{}
)

我感兴趣的是如何正确地为这个函数编写类型,尤其是返回类型,因为现在我将它隐式地设置为
any

updateFields
将具有返回类型
{[p in K]:V}&Omit
-将
字段中的所有属性
K
更新为值
V
,同时保留其余属性

reduce
操作中,如果一个新对象一个接一个地迭代构造,则总是需要某种形式的断言/强制转换。在具体示例中,您可以通过迭代
字段
数组而不是
T
的原始对象属性来简化函数体。这将把
键保存为K
强制转换和条件逻辑

const updateFields = <T extends object, K extends keyof T, V>(
  obj: T,
  callback: (val: T[K]) => V,
  fields: K[]
): Omit<T, K> & { [P in K]: V } => ({
  ...obj,
  ...fields.reduce(
    (acc, cur) => {
      // ... or use spread here
      acc[cur] = callback(obj[cur]);
      return acc;
    },
    {} as { [P in K]: V } // this cast is (almost always) necessary
  )
});

const foo = { a: 3, b: 4, c: "foo" };

// const bar: Pick<{a: number; b: number; c: string}, "c"> & {a: number; b: number;}
const bar = updateFields(foo, val => val + 10, ["a", "b"]);

console.log(bar); // { a: 13, b: 14, c: "foo" }