Is it possible to change the types of all matching keys in a nested interface?
I've tried a few different approaches with no luck. I'm trying to keep my type's generic signature as outlined in my examples. I want to specify the key/keys I want to change ("Target") and what types should be ("NewType"). I only want to identify the keys to change their types.
Please refer to my interface and its expected result below. My approaches for transforming the interface are below that.
It seems the second approach should work, but I don't know how to conditionally check the interface's leaf key values once the recursion ends (see conditional in the second example).
Here's a sandbox link as well.
Any help would be greatly appreciated. Thanks!
// 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",
};
APPROACH 1:
// transforming type
type ChangeTypeOfKeys_1<Obj, Target, NewType> = {
[K in keyof Obj]: K extends Target
? NewType
: Obj[K]
}
// type call
type dobby_1 = ChangeTypeOfKeys_1<og, 'elf', 'dobby'>
// result
type dobby_1 = {
a: number;
b: number;
c: {
a: number;
b: number;
characters: {
woman: string;
man: string;
elf: [boolean, string, number];
more: {
elf: boolean;
};
};
};
elf: "dobby";
}
APPROACH 2:
// transforming type
type ChangeTypeOfKeys_2<Obj, Target, NewType> = Obj extends object
? {
[K in keyof Obj]: ChangeTypeOfKeys_2<Obj[K], Target, NewType>
}
: NewType // <- how do I check the key's value in this conditional ???
// type call
type dobby_2 = ChangeTypeOfKeys_2<og, 'elf', 'dobby'>
// result
type dobby_2 = {
a: "dobby";
b: "dobby";
c: {
a: "dobby";
b: "dobby";
characters: {
woman: "dobby";
man: "dobby";
elf: ["dobby", "dobby", "dobby"];
more: {
elf: "dobby";
};
};
};
elf: "dobby";
}
SOLUTION (from Alex below):
Mainly here to show the on hover reference in the comments below and save anyone from overlooking something so simple, such as myself...
I've also added a solution sandbox with extended types and a description of what each does. The example interface has been modified for clarity.
// 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";
}