简体   繁体   English

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

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

Lets say I have an existing object obj1 = {a: 'A', b: 'B', c: 'C', d: 'D'}假设我有一个现有的对象obj1 = {a: 'A', b: 'B', c: 'C', d: 'D'}

I have another object something like obj2 = {b: 'B2', c: 'C2', d: 'D2', e: 'E2'}我有另一个对象,例如obj2 = {b: 'B2', c: 'C2', d: 'D2', e: 'E2'}

Now I want to selectively copy the values of only a few properties from obj2 to obj1 , for rest of the properties in obj1 , I want them unchanged.现在我想选择性地从只有几个属性的值复制obj2obj1中,对于性能的休息obj1 ,我希望他们保持不变。

Now, say I want to copy of the values of properties b and d .现在,假设我想复制属性bd的值。 I'd want to do something like我想做类似的事情

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'}

How do I write this method?这个方法怎么写? Note that I also do not want to provide the list of properties as strings, as I'd want compile time safety as much as possible.请注意,我也不想将属性列表提供为字符串,因为我希望尽可能保证编译时安全。

So basic asks here are:所以这里的基本问题是:

  1. Copy only a few property values from an object仅从对象复制几个属性值
  2. Copy to an existing object & not create a new one复制到现有对象而不是创建新对象
  3. Retain other property values in destination object在目标对象中保留其他属性值
  4. Avoid strings for property names (like 'b', 'd' ) and leverage TypeScript safety as much as possible避免使用字符串作为属性名称(如'b', 'd' )并尽可能利用TypeScript安全性

Clarification based on comment:基于评论的澄清:

When I say obj2.b or so in (pseudo) code example当我在(伪)代码示例中说obj2.b左右时

  • I do not mean literally obj2.b我的意思不是字面上的obj2.b
  • Rather some way to check at compile time that b is actually a property on obj2 's type而是在编译时检查b实际上是obj2类型的属性的某种方法

My suggestion for copyPropertyvalues() would be something like this:我对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;
}

The function is generic in the type T of the destination object, and the type K of the key names you're going to copy from the source to the destination object.该函数在目标对象的类型T以及您要从源复制到目标对象的键名的类型K中是通用的 I assume that you want to require that the properties you're copying from the source should be the same type as the properties already in the destination;我假设您想要求从源复制的属性应该与目标中已有的属性具有相同的类型; for example, you wouldn't copy the "a" property from a source of type {a: number} to a destination of type {a: string} , since you'd be writing a number to a string and violating the type of the destination.例如,你不会复制"a"从类型的源属性{a: number}到类型的目的地{a: string} ,因为你会写一个numberstring和违反的类型目的地。

Note that we don't need the source object to be exactly T ;请注意,我们不需要源对象正好是T it only has to agree with T at all the keys in K .它只需要在K中的所有键上与T一致。 That is, we only say that it must be Pick<T, K> using the Pick<T, K> utility type .也就是说,我们只说它必须是Pick<T, K>使用Pick<T, K>实用程序类型

And note that we are definitely passing in an array of key strings, which the compiler will infer not just as string , but specifically as a 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 ).并注意我们肯定是通过在关键字符串数组,该编译器会推断出不一样string ,而是专门为工会字符串字面类型它们的子集keyof T (使用keyof型运营商获得工会T的已知键)。 So if you pass in ["b", "d"] , the compiler will infer that as being of type Array<"b" | "d">因此,如果您传入["b", "d"] ,编译器会推断它的类型为Array<"b" | "d"> Array<"b" | "d"> and not just Array<string> . Array<"b" | "d">而不仅仅是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 ).这将为您提供您正在寻找的类型安全性,而无需担心诸如nameof类的nameof ,它在 JavaScript 中不存在(并且在 TypeScript 中不存在,直到它存在,请参阅microsoft/TypeScript#1579 )。


Okay, let's try it out:好的,让我们试一试:

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

Looks like it behaves how you want.看起来它的行为就像你想要的那样。 And if you put the wrong keys in there you get compile time errors:如果你把错误的键放在那里,你会得到编译时错误:

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

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

Playground link to code Playground 链接到代码

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM