I\'d like to map an object recursively so that the primitive values in the object are converted to some other type.
For example, I\'d like an object like this:
changing the type to
type ConvertToTest<T> = {
[P in keyof T]: T[P] extends any[]
? ConvertToTest<T[P]>
: T[P] extends string
? Test
: ConvertToTest<T[P]>
}
(extends string
instead of extends {}
) or
type ConvertToTest<T> = {
[P in keyof T]: T[P] extends any[]
? ConvertToTest<T[P]>
: T[P] extends object
? ConvertToTest<T[P]>
: Test
}
(extends object
instead of extends {}
)
seems to do the trick.
So you need two things from the ConvertToTest<T>
type. One is that if T
is a primitive type, then CovertToTest<T> = Test
. The other is that if T
isn't primitive, you want to keep the same keys but convert their values.
To do that, I'd just add the first case as one part of a conditional type, and then have the other branch use a recursive mapped type:
type Primitive = string | number | boolean | null | undefined;
type ConvertToTest<T> = T extends Primitive ? Test : {
[K in keyof T]:
T[K] extends (infer U)[] ? ConvertToTest<U>[] :
ConvertToTest<T[K]>;
}
Using that, you can then use it like so:
// For example. Replace with whatever your actual type is.
type test = {
foo(): string;
}
declare function convertToTest<T>(obj: T): ConvertToTest<T>;
const test = convertToTest({ a: "", b: { c: true, primArr: [1, ""], objArr: [{inner: ""}] } });
test.a.foo(); // OK
test.b.c.foo(); // OK
test.b.primArr[0].foo() // OK
test.b.objArr[0].inner.foo() // OK
This is a nice way to do it since it will work for objects of any depth, and will properly handle converting the elements of an array type as well.
You were really close. The problem here is that string
is assignable to {}
.
Demonstration of this fact here.
If you check for the string, number, etc. first before {}
, then you can get what you want:
type ConvertToTest<T> = {
[P in keyof T]: T[P] extends any[]
? ConvertToTest<T[P]>
: T[P] extends string
? Test
: T[P] extends number
? Test
: T[P] extends boolean
? Test
: ConvertToTest<T[P]>
}