Typescript 基于任意属性名复制值
我有一个类型a,有几个属性,可以是不同的键:字符串、数字、类型B、无关。我想在某些字段上从类型为A的对象a1复制到类型为A的对象a2,但我事先不知道要复制哪些字段。我要复制的字段包含在一个字符串文本数组中,它告诉我要复制哪个字段Typescript 基于任意属性名复制值,typescript,Typescript,我有一个类型a,有几个属性,可以是不同的键:字符串、数字、类型B、无关。我想在某些字段上从类型为A的对象a1复制到类型为A的对象a2,但我事先不知道要复制哪些字段。我要复制的字段包含在一个字符串文本数组中,它告诉我要复制哪个字段 type A = { name: string, length: number, thing: B } const a1: A = { name: "test", length: 2, thing: { whatever
type A = {
name: string,
length: number,
thing: B
}
const a1: A = {
name: "test",
length: 2,
thing: { whatever: true },
}
const a2: A = {
name: "",
length: 0,
thing: {whatever: false}
}
const propNames = ["name", "length"]
propNames.map(propName => a2[propName] = a1[propName as keyof A])
如果有任何可能的帮助,我将不胜感激,以下是沙盒上的示例:
reduce
函数copyPropertiesOver(属性:string[],源:E,目标:E):E{
常数值stobecopied=arr.reduce(
(acc,curr)=>({…acc,curr:source[curr as keyof E]}),
{}
);
const targetUpdated=({…target,…valuesToBeCopied}未知)作为E;
返回目标更新;
}
const a2Updated=copyPropertiesOver
确定包含要复制的所有键/值的对象李>
从空对象开始,对要复制的每个属性使用reduce
将目标对象与要覆盖的值组合李>
函数copyPropertiesOver(属性:string[],源:E,目标:E):E{
常数值stobecopied=arr.reduce(
(acc,curr)=>({…acc,curr:source[curr as keyof E]}),
{}
);
const targetUpdated=({…target,…valuesToBeCopied}未知)作为E;
返回目标更新;
}
const a2Updated=copyPropertiesOver如果编写const arr=[“some”,“strings”]
编译器将推断arr
属于string[]
类型,它将立即忘记其内容的确切数字和值。这通常是正确的行为,因为人们确实倾向于改变数组的内容(即使是const
的数组也可以有arr[0]=“赋值”
和arr.push(“push”);
)
如果希望编译器跟踪数组文字中的特定内容,则需要更改声明变量的方式。最简单的方法是在TypeScript 3.4中介绍的:
const arr = ["name", "length"] as const;
现在已知arr
的类型是一个长度为2的数组,其第一个元素必须是“name”
,第二个元素必须是“length”
。因此,如果您编写arr.map(propName=>…)
,编译器将知道propName
必须是“name”|“length”
如果你解决了这个问题,你将面临的第二个问题是:
这里的问题是编译器认为赋值可能不安全,因为它无法验证a2[propName]
设置的属性与您从a1[propName]
读取的属性完全相同。这对我们来说很明显,因为变量propName
是相同的,但编译器看到的是这些访问使用相同的键类型,这是两种可能的联合,有四种可能的结果,如下所示:
const propName2 = arr[Math.random() < 0.5 ? 0 : 1];
const propName1 = arr[Math.random() < 0.5 ? 0 : 1];
a2[propName2] = a1[propName1]; // same error!
在本例中,编译器看到您正在将a[K]
类型的值赋给a[K]
类型的值。这就是我建议你继续的方式
好吧,希望这会有帮助;祝你好运
如果编写const arr=[“some”,“strings”]
编译器将推断arr
属于string[]
类型,它将立即忘记其内容的确切数字和值。这通常是正确的行为,因为人们确实倾向于改变数组的内容(即使是const
的数组也可以有arr[0]=“赋值”
和arr.push(“push”);
)
如果希望编译器跟踪数组文字中的特定内容,则需要更改声明变量的方式。最简单的方法是在TypeScript 3.4中介绍的:
const arr = ["name", "length"] as const;
现在已知arr
的类型是一个长度为2的数组,其第一个元素必须是“name”
,第二个元素必须是“length”
。因此,如果您编写arr.map(propName=>…)
,编译器将知道propName
必须是“name”|“length”
如果你解决了这个问题,你将面临的第二个问题是:
这里的问题是编译器认为赋值可能不安全,因为它无法验证a2[propName]
设置的属性与您从a1[propName]
读取的属性完全相同。这对我们来说很明显,因为变量propName
是相同的,但编译器看到的是这些访问使用相同的键类型,这是两种可能的联合,有四种可能的结果,如下所示:
const propName2 = arr[Math.random() < 0.5 ? 0 : 1];
const propName1 = arr[Math.random() < 0.5 ? 0 : 1];
a2[propName2] = a1[propName1]; // same error!
在本例中,编译器看到您正在将a[K]
类型的值赋给a[K]
类型的值。这就是我建议你继续的方式
好吧,希望这会有帮助;祝你好运
我最终使用的是将我的a1和a2对象强制转换为A&Record
,因为这是最优雅、对我来说最容易理解的解决方案
const a1 = {
name: "test",
length: 2,
thing: { whatever: true }
} as A & Record<string, any>;
const a2 = {
name: "",
length: 0,
thing: { whatever: false }
} as A & Record<string, any>;
arr.filter(propName => propName in a2).forEach(propName => (a2[propName] = a1[propName]));
const a1={
名称:“测试”,
长度:2,
事情:{无论如何:真的}
}作为记录;
常数a2={
姓名:“,
长度:0,
事情:{无论如何:错}
}作为记录;
arr.filter(a2.forEach中的propName=>propName)(propName=>(a2[propName]=a1[propName]);
当然,在实际的生产解决方案中,我使用in
type操作符首先检查字符串是否是对象中的实际字段名。
if(a2中的“值”)等
etc..我最终使用的是将a1和a2对象转换为A&Record
,因为这是最优雅的解决方案,对我来说也是可以理解的
const a1 = {
name: "test",
length: 2,
thing: { whatever: true }
} as A & Record<string, any>;
const a2 = {
name: "",
length: 0,
thing: { whatever: false }
} as A & Record<string, any>;
arr.filter(propName => propName in a2).forEach(propName => (a2[propName] = a1[propName]));
<