如何仅将对象属性子集的值复制到 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
中的其余属性,我希望它们保持不变。
现在,假设我要复制属性 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;
}
目标对象的类型T
中的函数是generic,并且您要从源复制到目标的键名称的类型是K
目的。我假设您想要要求从源复制的属性应该与目标中已有的属性具有相同的类型;例如,您不会将 "a"
属性 从类型 {a: number}
的源复制到类型 {a: string}
的目标,因为您将编写 number
到 string
并违反目标类型。
请注意,我们不需要源对象完全 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"]
)
假设我有一个现有对象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;
}
目标对象的类型T
中的函数是generic,并且您要从源复制到目标的键名称的类型是K
目的。我假设您想要要求从源复制的属性应该与目标中已有的属性具有相同的类型;例如,您不会将 "a"
属性 从类型 {a: number}
的源复制到类型 {a: string}
的目标,因为您将编写 number
到 string
并违反目标类型。
请注意,我们不需要源对象完全 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"]
)