Typescript,更改接口中嵌套的所有匹配键的类型

Typescript,更改接口中嵌套的所有匹配键的类型,typescript,recursion,interface,nested,typescript-typings,Typescript,Recursion,Interface,Nested,Typescript Typings,是否可以更改嵌套接口中所有匹配键的类型 我尝试过几种不同的方法,但都没有成功。我试图保持我的类型的泛型签名,如我的示例中所述。我想指定要更改的键(“Target”)以及应该是什么类型(“NewType”)。我只想确定更改其类型的键 请参考下面我的界面及其预期结果。下面是我转换接口的方法 第二种方法似乎可以工作,但我不知道在递归结束后如何有条件地检查接口的叶键值(参见第二个示例中的条件) 任何帮助都将不胜感激。谢谢 // interface interface og { a: numb

是否可以更改嵌套接口中所有匹配键的类型

我尝试过几种不同的方法,但都没有成功。我试图保持我的类型的泛型签名,如我的示例中所述。我想指定要更改的键(“Target”)以及应该是什么类型(“NewType”)。我只想确定更改其类型的键

请参考下面我的界面及其预期结果。下面是我转换接口的方法

第二种方法似乎可以工作,但我不知道在递归结束后如何有条件地检查接口的叶键值(参见第二个示例中的条件)

任何帮助都将不胜感激。谢谢

// interface 
interface og {
    a: number,
    b: number,
    c: {
        a: number,
        b: number,
        characters: {
            woman: string,
            man: string,
            elf: [boolean, string, number]
            more: {
                elf: boolean
            }
        },
    },
    elf: boolean,
};

// desired transform result (I know "dobby" isn't a typical type)
type og_transformed = {
    a: number,
    b: number,
    c: {
        a: number,
        b: number,
        characters: {
            woman: string,
            man: string,
            elf: ["dobby", "dobby", "dobby"] 
            more: {
                elf: "dobby"
            }
        },
    },
    elf: "dobby",
};

// this result could be accepted as well
type og_transformed = {
    a: number,
    b: number,
    c: {
        a: number,
        b: number,
        characters: {
            woman: string,
            man: string,
            elf: "dobby" // <- this is different
            more: {
                elf: "dobby"
            }
        },
    },
    elf: "dobby",
};
//接口
接口og{
a:号码,
b:号码,
c:{
a:号码,
b:号码,
人物:{
女人:绳子,
男人:绳子,
elf:[布尔值、字符串、数字]
更多:{
布尔型
}
},
},
小精灵:布尔,
};
//所需的变换结果(我知道“dobby”不是典型类型)
类型og_转换={
a:号码,
b:号码,
c:{
a:号码,
b:号码,
人物:{
女人:绳子,
男人:绳子,
精灵:[“多比”、“多比”、“多比”]
更多:{
小精灵:“多比”
}
},
},
精灵:“多比”,
};
//这一结果也可以接受
类型og_转换={
a:号码,
b:号码,
c:{
a:号码,
b:号码,
人物:{
女人:绳子,
男人:绳子,

elf:“dobby”//您确实需要递归来深入嵌套对象。但实际上您需要做两个条件测试:

  • 这是一把应该更换的钥匙吗?您已经在这样做了
  • 这个值是一个需要递归的对象吗?如果是,递归,否则我们只返回它的类型不变
  • 你的两次尝试都完成了一半。你需要将它们组合成一个嵌套的条件类型来执行这两项检查

    type ChangeTypeOfKeys<Obj, Target, NewType> = {
        [K in keyof Obj]:
    
            // does this value have the target key? If so replace it.
            K extends Target ? NewType 
    
            // Else, is this value an object? If so, recursively change call ChangeTypeOfKeys
            : Obj[K] extends object ? ChangeTypeOfKeys<Obj[K], Target, NewType>
    
            // Else, use the type of this leaf without modification.
            : Obj[K]
    }
    
    type OgTransformed = ChangeTypeOfKeys<Og, 'elf', 'dobby'>
    declare const elfed: OgTransformed
    const elfName = elfed.c.characters.elf // type: 'dobby'
    const elfMore = elfed.c.characters.more.elf // type: 'dobby'
    
    type ChangeTypeOfKeys={
    [K in keyof Obj]:
    //此值是否有目标键?如果有,请将其替换。
    K扩展目标?新类型
    //否则,这个值是对象吗?如果是,递归地更改调用ChangeTypeOfKeys
    :Obj[K]扩展对象?更改键的类型
    //否则,请使用此叶的类型而不进行修改。
    :Obj[K]
    }
    类型=ChangeTypeOfKeys
    声明const-elfed:OgTransformed
    const elfName=elfed.c.characters.elf//type:'dobby'
    const elfMore=elfed.c.characters.more.elf//type:'dobby'
    

    要深入嵌套对象,您肯定需要它是递归的。但实际上,您需要做两个条件测试:

  • 这是一把应该更换的钥匙吗?您已经在这样做了
  • 这个值是一个需要递归的对象吗?如果是,递归,否则我们只返回它的类型不变
  • 你的两次尝试都完成了一半。你需要将它们组合成一个嵌套的条件类型来执行这两项检查

    type ChangeTypeOfKeys<Obj, Target, NewType> = {
        [K in keyof Obj]:
    
            // does this value have the target key? If so replace it.
            K extends Target ? NewType 
    
            // Else, is this value an object? If so, recursively change call ChangeTypeOfKeys
            : Obj[K] extends object ? ChangeTypeOfKeys<Obj[K], Target, NewType>
    
            // Else, use the type of this leaf without modification.
            : Obj[K]
    }
    
    type OgTransformed = ChangeTypeOfKeys<Og, 'elf', 'dobby'>
    declare const elfed: OgTransformed
    const elfName = elfed.c.characters.elf // type: 'dobby'
    const elfMore = elfed.c.characters.more.elf // type: 'dobby'
    
    type ChangeTypeOfKeys={
    [K in keyof Obj]:
    //此值是否有目标键?如果有,请将其替换。
    K扩展目标?新类型
    //否则,这个值是对象吗?如果是,递归地更改调用ChangeTypeOfKeys
    :Obj[K]扩展对象?更改键的类型
    //否则,请使用此叶的类型而不进行修改。
    :Obj[K]
    }
    类型=ChangeTypeOfKeys
    声明const-elfed:OgTransformed
    const elfName=elfed.c.characters.elf//type:'dobby'
    const elfMore=elfed.c.characters.more.elf//type:'dobby'
    

    Ahh。非常感谢您简洁的回答。它工作得非常完美。从您的回答中,我意识到我在其他迭代中确实正确地设置了转换器类型。不幸的是,我没有意识到悬停时TS不会在界面上显示所有类型。它只是显示转换器类型的下一个递归。我不知道你实际上必须像你在回答结束时那样声明性地访问类型。直到。我已经在我的原始帖子中为可能阅读本文的任何人介绍了我在hover上谈论的内容。是的,类型脚本并不总是完全处理工具提示中的类型。请注意,内部类型是如何包装在
    ChangeTypeOfKeys
    中的,这意味着初始化要转换的输入类型和执行转换的类型别名。从的嵌套值中获取实际类型需要钻取它。啊。非常感谢您简洁的回答。它工作得非常好。从您的回答中,我意识到我在其他迭代中确实正确设置了转换器类型。不幸的是,我没有意识到OnHover TS并没有在界面上显示所有类型。它只是显示transformer类型的下一个递归。我不知道你实际上必须像在回答结束时那样以声明方式访问这些类型。直到。我已经在我的原始帖子中为那些可能ead this.Yeah type脚本并不总是完全处理工具提示中的类型。请注意内部类型是如何包装在
    ChangeTypeOfKeys
    中的,这表示要转换的输入类型和执行转换的类型别名。从嵌套的值获取真正的类型需要钻取它。
    // transforming type
    type ChangeTypeOfKeys_3<Obj, Target, NewType> = {
        [K in keyof Obj]: K extends Target 
            ? NewType
            : Obj[K] extends object 
                ? ChangeTypeOfKeys_3<Obj[K], Target, NewType>
                : Obj[K]
    }
    
    // type call
    type dobby_3 = ChangeTypeOfKeys_3<og, 'elf', 'dobby'>
    
    // result (on hover)
    type dobby_3 = {
        a: number;
        b: number;
        c: ChangeTypeOfKeys_3<{
            a: number;
            b: number;
            characters: {
                woman: string;
                man: string;
                elf: [boolean, string, number];
                more: {
                    elf: boolean;
                };
            };
        }, "elf", "dobby">;
        elf: "dobby";
    }
    
    type ChangeTypeOfKeys<Obj, Target, NewType> = {
        [K in keyof Obj]:
    
            // does this value have the target key? If so replace it.
            K extends Target ? NewType 
    
            // Else, is this value an object? If so, recursively change call ChangeTypeOfKeys
            : Obj[K] extends object ? ChangeTypeOfKeys<Obj[K], Target, NewType>
    
            // Else, use the type of this leaf without modification.
            : Obj[K]
    }
    
    type OgTransformed = ChangeTypeOfKeys<Og, 'elf', 'dobby'>
    declare const elfed: OgTransformed
    const elfName = elfed.c.characters.elf // type: 'dobby'
    const elfMore = elfed.c.characters.more.elf // type: 'dobby'