如何仅将对象属性子集的值复制到 TypeScript 中的另一个现有对象

How to copy values of only a subset of object properties to another existing object in TypeScript

假设我有一个现有对象obj1 = {a: 'A', b: 'B', c: 'C', d: 'D'}

我还有一个类似 obj2 = {b: 'B2', c: 'C2', d: 'D2', e: 'E2'}

的对象

现在我想有选择地只复制 obj2 中少数属性的值到 obj1,对于 obj1 中的其余属性,我希望它们保持不变。

现在,假设我要复制属性 bd 的值。我想做类似

的事情
obj1 = {a: 'A', b: 'B', c: 'C', d: 'D'};
obj2 = {b: 'B2', c: 'C2', d: 'D2', e: 'E2'};

copyPropertyvalues(
    obj2, // source
    obj1, // destination
    [obj2.b, obj2.d] // properties to copy >> see clarification below
); // should result in obj1 = {a: 'A', b: 'B2', c: 'C', d: 'D2'}

这个方法怎么写?请注意,我也不想以字符串形式提供属性列表,因为我希望编译时尽可能安全。

这里的基本问题是:

  1. 从一个对象中仅复制几个 属性 值
  2. 复制到现有对象而不创建新对象
  3. 在目标对象中保留其他 属性 值
  4. 避免 属性 名称的字符串(如 'b', 'd')并尽可能利用 TypeScript 安全性

基于评论的澄清:

当我在(伪)代码示例中说 obj2.b 左右时

我对 copyPropertyvalues() 的建议是这样的:

function copyPropertyvalues<T, K extends keyof T>(s: Pick<T, K>, d: T, ks: K[]) {
    ks.forEach(k => d[k] = s[k]);
    return d;
}

目标对象的类型T中的函数是generic,并且您要从源复制到目标的键名称的类型是K目的。我假设您想要要求从源复制的属性应该与目标中已有的属性具有相同的类型;例如,您不会将 "a" 属性 从类型 {a: number} 的源复制到类型 {a: string} 的目标,因为您将编写 numberstring 并违反目标类型。

请注意,我们不需要源对象完全 T;它只需要在 K 中的所有键上与 T 一致。即我们只说必须是Pick<T, K> using the Pick<T, K> utility type.

请注意,我们肯定会传递一个键字符串数组,编译器将不仅将其推断为 string,而且将其推断为 union of string literal types which are a subset of keyof T (using the keyof type operator to get a union of the known keys of T). So if you pass in ["b", "d"], the compiler will infer that as being of type Array<"b" | "d"> and not just Array<string>. This will give you the type safety you're looking for, without trying to worry about something like nameof which does not exist in JavaScript (and will not exist in TypeScript until it does, see microsoft/TypeScript#1579)。


好吧,让我们试试看:

copyPropertyvalues(
    obj2, // source
    obj1, // destination
    ["b", "d"] // properties to copy
);
console.log(obj1)
/* {
  "a": "A",
  "b": "B2",
  "c": "C",
  "d": "D2"
}  */

看起来它的行为符合您的要求。如果你把错误的键放在那里,你会得到编译时错误:

copyPropertyvalues(
    obj2, // error!
    obj1,
    ["a"]
)

copyPropertyvalues(
    obj2,// error!
    obj1,
    ["z"]
)

Playground link to code