I need to recursively get through the data structure and create a type that has some of the fields changed to a different type, based on a condition.
Based on the following structure, I need to create a type (Result) where all A types are replaced with B types.
class A{}
class B{}
const data = {
propA:new AA,
propB:true,
nested:{
propC:new AA,
propD:false
}
}
// something like:
type Replace<typeof data, A, B>
// result
type Result = {
propA:B,
propB:boolean,
nested:{
propC:B
propD:boolean
}
}
You can do this with a mapped type, but keep in mind that matching is based on object structure rather than class name, so an object from a class C{} will also get converted when you're targeting A.
The Replace type can be defined as
type Replace<T, From, To> = T extends (...args: any[]) => any ? T : {
[K in keyof T]:
[T[K], From] extends [From, T[K]] ? To : Replace<T[K], From, To>
}
The first condition is to preserve any methods/function properties as mapped types will convert these to {}. The mapped type itself processes each key, and checks whether both value extends the From type and the From type extends the value type, to ensure equality. If both are equal, the value gets replaced with To, and otherwise Replace is called recursively.
Here's an example conversion:
class A{}
class B{b = 42}
class C{}
const data = {
propA: new A(),
propBool: true,
propC: new C(),
nested:{
propA: new A(),
propBool: false
},
f: () => 42
}
type Result = Replace<typeof data, A, B>
// type Result = {
// propA: B;
// propBool: boolean;
// propC: B;
// nested: {
// propA: B;
// propBool: boolean;
// };
// f: () => number;
// }
TypeScript playground
This can be achieved with conditional, recursive types:
class A {
ClassPropA!: string
}
class B {
ClassPropB!: string
}
const data = {
propA: new A(),
propB: true,
nested:{
propC: new A(),
propD:false
}
}
type Replace<T, A, B> = T extends object
? { [key in keyof T]: T[key] extends A ? B : Replace<T[key], A, B> }
: T;
// type Result = {
// propA: B,
// propB: boolean,
// nested:{
// propC: B
// propD: boolean
// }
//
// }
type Result = Replace<typeof data, A, B>;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With