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