我想以递归方式映射对象,以便将对象中的原始值转换为其他类型。
例如,我想要一个像这样的对象:
const before = { a: { c: '' }, b: [ '', { d: '' } ] }
成为这个:
const after = { a: { c: Test }, b: [ Test, { d: Test } ] }
我还假设值不是Date
,Symbol
或null / void。只是JSON可序列化的类型,如字符串,数字等(除了null)
这是我试过的:
type ConvertToTest<T> = {
[P in keyof T]: T[P] extends any[]
? ConvertToTest<T[P]>
: T[P] extends {}
? ConvertToTest<T[P]>
: Test;
}
function convert<T>(o: T): ConvertToTest<T> {
// ...
}
这是使用Typescript 2.8中引入的conditional types。
const after = convert(before)
会在after.a.c
的编辑器中生成string
c
个类型的完成,而不是Test
的完成。
如何重写type ConvertToTest<T>
以说服after.a.c
类型为Test
的打字稿?
编辑:以下是Typescript Playground link说明以上内容。
答案 0 :(得分:3)
所以你需要ConvertToTest<T>
类型的两件事。一个是如果T
是基本类型,那么CovertToTest<T> = Test
。另一种情况是,如果T
不是原始的,您希望保留相同的键但转换它们的值。
为此,我只是将第一个案例添加为条件类型的一部分,然后让另一个分支使用递归映射类型:
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]>;
}
使用它,您可以像这样使用它:
// 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
这是一种很好的方法,因为它可以用于任何深度的对象,并且也可以正确处理转换数组类型的元素。
答案 1 :(得分:0)
将类型更改为
type ConvertToTest<T> = {
[P in keyof T]: T[P] extends any[]
? ConvertToTest<T[P]>
: T[P] extends string
? Test
: ConvertToTest<T[P]>
}
(extends string
代替extends {}
)或
type ConvertToTest<T> = {
[P in keyof T]: T[P] extends any[]
? ConvertToTest<T[P]>
: T[P] extends object
? ConvertToTest<T[P]>
: Test
}
(extends object
代替extends {}
)
似乎可以解决问题。
答案 2 :(得分:0)
你真的很亲密。这里的问题是string
可分配给{}
。
证明这一事实here。
如果您在{}
之前先检查字符串,数字等,那么您可以得到您想要的内容:
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]>
}