Javascript Typescript函数在特定路径处合并对象
我有一个合并函数,可以在特定路径上合并对象Javascript Typescript函数在特定路径处合并对象,javascript,typescript,typescript-generics,Javascript,Typescript,Typescript Generics,我有一个合并函数,可以在特定路径上合并对象 const merge=(src,path,newObj)=>{ //这个代码很好用 } 要使用此函数,我将其称为: 接口IUser{ 用户:{ 地址:{ 街道:字符串 } } } 接口IAddrNum{ 门:号码 } 常量用户:IUser={ 用户:{ 地址:{ 街道:“新街” } } } 常量合并对象:IAddrNum={ 门:59 } const newObj=merge(用户,“User.address”,mergeObj); 这样,我得到
const merge=(src,path,newObj)=>{
//这个代码很好用
}
要使用此函数,我将其称为:
接口IUser{
用户:{
地址:{
街道:字符串
}
}
}
接口IAddrNum{
门:号码
}
常量用户:IUser={
用户:{
地址:{
街道:“新街”
}
}
}
常量合并对象:IAddrNum={
门:59
}
const newObj=merge(用户,“User.address”,mergeObj);
这样,我得到了正确的结果
{
user: {
address: {
street: "New Street"
door: 59
}
}
}
问题:我想在typescript中为此函数创建签名
接口不可变{
合并(
src:T,
路径:K,
合并:M
):T&M//如果您可以使用路径元组,那么我们需要处理元组。一个有用的类型别名是Tail
,它采用类似[string,number,boolean]
的元组类型,并返回第一个元素已删除的另一个元组,如[number,boolean]
:
type Tail<T extends any[]> =
((...t: T) => void) extends ((h: any, ...r: infer R) => void) ? R : never;
为了确保这一点,这里有一个例子“
最后,我们可以给merge()
一个类型签名(和一个实现,尽管这超出了问题的范围,也不能保证是正确的):
我想看起来不错。好吧,希望能有帮助,祝你好运
由于编译器无法在类型级别解析字符串,因此无法使用“user.address”
来执行此操作。相反,您需要使用类似元组的形式[“user”,“address”]作为常量来开始编写此操作。或者您可以将合并参数设置为自己的对象,如{user:{address:{door:59}}
并且根本不提路径(在这种情况下,返回类型看起来确实有点像T&M
)。我很乐意就这两个选项中的任何一个提供建议,但虚线路径字符串文字是不可行的。谢谢@jcalz。我不确定“user.address“
会有用的。谢谢你的解释。我可以做它”[“用户”,“地址”]
。如果您能指导我进行这项新的更改,那就太好了。感谢@jcalz的精彩解释,并对其进行详细分析,以便我理解。这非常有效。根据您的代码,我正在尝试为del
编写一个类型。在这种情况下,它将是del(User,[“User”,“address”,“street]”)
。你能指导我吗?我已经修改了DeepRecord
来创建对象,但我无法从源对象中减去它。这是一个不同的问题,不是吗?我很乐意看一下,但不在评论部分(你可能想发布一个新的问题,以吸引其他人的注意,以防我找不到它)当然,这是我刚刚发布的链接-
type DeepRecord<K extends PropertyKey[], V> =
K extends [] ? V : { [P in K[0]]: DeepRecord<Tail<K>, V> };
type Example = DeepRecord<["foo", "bar", "baz"], string>;
/* type Example = { foo: { bar: { baz: string; }; };} */
type MergeIntersection<T> =
T extends object ? { [K in keyof T]: MergeIntersection<T[K]> } : T;
const merge = <T extends object, K extends N[] | [],
V extends object, N extends PropertyKey>(
src: T, path: K, newObj: V
) => {
const ret = { ...src } as MergeIntersection<T & DeepRecord<K, V>>;
let obj: any = ret;
for (let k of path) {
if (!(k in obj)) {
obj[k] = {};
}
obj = obj[k];
}
Object.assign(obj, newObj);
return ret;
}
const newObj = merge(User, ["user", "address"], mergeObj);
/* const newObj: {
user: {
address: {
street: string;
door: number;
};
};
}*/
console.log(JSON.stringify(newObj));
// {"user":{"address":{"street":"New Street","door":59}}}