I want to replace a specific type with another type, as so:
interface Human {
name: string;
age: number;
isMarried: boolean;
animals: [
{ name: string, age: number},
{ name: string, age: number}
]
}
type HumanString = ReplaceTypes<Human, number, string>
/*
HumanString {
name: string;
age: string;
isMarried: boolean;
animals: [
{ name: string, age: string},
{ name: string, age: string}
]
}
*/
Where the has the following interface ReplaceTypes<OriginalType, OldType, NewType>
Oldtype
should be replaced in all nested occurances for NewType
CodePudding user response:
You can do that with a recursive mapped type that looks like this:
type ReplaceTypes<ObjType extends object, FromType, ToType> = {
[KeyType in keyof ObjType]: ObjType[KeyType] extends object
? ReplaceTypes<ObjType[KeyType], FromType, ToType> // Recurse
: ObjType[KeyType] extends FromType // Not recursing, need to change?
? ToType // Yes, change it
: ObjType[KeyType]; // No, keep original
}
So for instance, if you had example: HumanString
, example.age
and example.animals[number].age
would both be string
instead of number
.
It looks to see if the type of each property extends object and if so, recurses; otherwise, it looks to see if the type extends the "from" type and replaces it if so.
All of those repeated instances of ObjType[KeyType]
get tiresome, so you could split it up into two parts:
type ReplaceType<Type, FromType, ToType> =
Type extends object
? ReplaceTypes<Type, FromType, ToType>
: Type extends FromType
? ToType
: Type;
type ReplaceTypes<ObjType extends object, FromType, ToType> = {
[KeyType in keyof ObjType]: ReplaceType<ObjType[KeyType], FromType, ToType>;
}
If you wanted to be able to do this with FromType
being an object, type, it should work if you change the order:
type ReplaceType<Type, FromType, ToType> =
Type extends FromType // FromType?
? ToType // Yes, replace it
: Type extends object // Recurse?
? ReplaceTypes<Type, FromType, ToType> // Yes
: Type; // No, leave it alone
type ReplaceTypes<ObjType extends object, FromType, ToType> = {
[KeyType in keyof ObjType]: ReplaceType<ObjType[KeyType], FromType, ToType>;
}