type someObj = {
a: number,
b: Array<string>,
c: { d: string },
e: {
f: string,
g: Array<{
h: string,
i: Array<number>
}>
},
j: {
k: string,
l: Array<string>
},
m: Array<Array<string>>
};
type someGeneric<T /* can be primitive, array or object */> = ???;
// Expected Result
type someObjGenericResult = {
b: (item: string) => void,
e: {
g: (item: { h: string, i: Array<number> }) => {
i: (item: number) => void
}
},
j: { l: (item: string) => void },
m: (item: Array<string>) => (item: string) => void
};因此,我希望编写一个泛型,它将接受任意值,并在对象中的每个数组上执行一个函数(不管它是如何嵌套的),并具有以下属性
=>排除所有原语(比如某个Obj.a)
=>排除没有将数组作为类型的支柱的对象(例如
=>,但是包含一个对象,它有一个数组作为支柱(比如omeObj.j)。
=>用户竞相寻找具有嵌套数组的数组(比如一些Obj.m)。
发布于 2019-02-01 02:23:09
因问题更改而更新
如果您只是研究如何进行类型输入(而不是将someObj实例转换为someObjGenericResult实例的运行时代码),我认为以下内容将有效:
// HasNestedArrays<T> outputs unknown (meaning true) or never (meaning false)
// depending on whether T is an array or an object with at least one
// property that HasNestedArrays itself. This is a recursive definition.
// HasNestedArrays<{a: {b: {c: string[]}}}> should return unknown,
// HasNestedArrays<{a: {b: {c: string}}}> should return never.
type HasNestedArrays<T> = T extends Array<any> ? unknown :
T extends object ? { [K in keyof T]: HasNestedArrays<T[K]> }[keyof T] : never;
// PickHasNestedArrays<T> takes an object type T and removes any properties
// that do not pass the HasNestedArrays test.
// PickHasNestedArrays<{a: string, b: string[], c: {d: string[]}}> should return
// {b: string[], c: {d: string[]}}.
type PickHasNestedArrays<T extends object> = Pick<T,
{ [K in keyof T]: unknown extends HasNestedArrays<T[K]> ? K : never }[keyof T]
>
// SomeGeneric<T> is the type you want:
// If T is an array like U[], return a function (item: U) => SomeGeneric<U>.
// If T is an object, strip all the non-array-containing properties out
// (via PickHasNestedArrays<T>) and assign the stripped object to V.
// If V is an empty object, then return void.
// Otherwise, return a new object whose properties have the same keys K from V
// but whose values are SomeGeneric<V[K]>.
type SomeGeneric<T> = T extends Array<infer U> ?
(item: U) => SomeGeneric<U> :
T extends object ? (
PickHasNestedArrays<T> extends infer V ? (
{} extends V ? void : { [K in keyof V]: SomeGeneric<V[K]> }
) : never
) : void;
type someObjGenericResult = SomeGeneric<someObj>;注意,在TypeScript中,unknown是所谓的顶型,它包含所有的值.这基本上是类型的“真实”。never就是所谓的底式,它不包含任何值.这基本上是类型的“假”。当我执行类似布尔型的类型操作时,我倾向于输出unknown/never用于true/false,因为它有时会使后续操作更容易。
HasNestedArrays<T>和PickHasNestedArrays<T>类型用于去掉您不关心的T的所有属性。SomeGeneric<T>是您所要求的类型函数。我已经在上面的注释中解释了它们所做的事情,但是它们的工作方式需要理解条件类型、映射类型和查找类型。如果您了解所有的表示法,并需要更多关于在某些情况下正在发生的事情的细节,我可以详细说明。
我不确定SomeGeneric<T>是否是您真正想要的,因为有一些边缘情况,如SomeGeneric<number>、SomeGeneric<{a: number}>等等。我非常肯定,上面的定义为大多数边缘情况下的void。
不管怎么说,我希望这能帮上忙。祝好运!
https://stackoverflow.com/questions/54467264
复制相似问题