假设我有一个现有对象 obj1 = {a: 'A', b: 'B', c: 'C', d: 'D'}
我有另一个对象,如 obj2 = {b: 'B2', c: 'C2', d: 'D2', e: 'E2'}
现在我想有选择地仅将少数属性的值从 obj2
复制到 obj1
,对于 obj1
中的其余属性,我希望它们不变。
现在,假设我想复制属性 b
和 d
的值。我想做类似的事情
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'}
这个方法怎么写?请注意,我也不想以字符串形式提供属性列表,因为我希望编译时尽可能安全。
这里的基本问题是:
- 仅复制对象中的几个属性值
- 复制到现有对象而不创建新对象
- 保留目标对象中的其他属性值
- 避免使用字符串作为属性名称(如
'b'、'd'
)并尽可能利用TypeScript
安全性
基于评论的澄清:
当我在(伪)代码示例中说obj2.b
左右
- 我不是字面上的意思
obj2.b
- 而是一些在编译时检查
b
实际上是obj2
类型的属性
最佳答案
我对 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;
}
函数是generic在类型 T
目标对象的类型,以及类型 K
您要从源对象复制到目标对象的键名。我假设您想要要求从源复制的属性应该与目标中已有的属性具有相同的类型;例如,您不会复制 "a"
来自类型来源的属性 {a: number}
到类型为 {a: string}
的目的地,因为你会写一个 number
到 string
并违反了目的地的类型。
请注意,我们不需要源对象正好是 T
;它只需要同意 T
在 K
中的所有键.即我们只说一定是Pick<T, K>
使用 the Pick<T, K>
utility type .
请注意,我们肯定传递了一个键字符串数组,编译器将其推断为不只是 string
。 , 但特别是 union字符串 literal types这是 keyof T
的子集(使用 the keyof
type operator 获取 T
的已知键的并集)。所以如果你传入 ["b", "d"]
, 编译器将推断其为 Array<"b" | "d">
类型而不仅仅是 Array<string>
.这将为您提供您正在寻找的类型安全性,而无需担心 nameof
之类的问题。它在 JavaScript 中不存在(并且在它存在之前不会存在于 TypeScript 中,请参阅 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"]
)
关于javascript - 如何仅将对象属性子集的值复制到 TypeScript 中的另一个现有对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69993223/