匹配 Typescript 中的通用嵌套对象类型
Match generic nested object type in Typescript
假设我有一个嵌套对象类型来定义,比方说,一个用户:
type TestUser = {
name: string;
email: string;
houses: {
address: string;
rooms: {
floor: number;
color: string;
connectedTo: {
id: number;
}[];
}[];
doors: {
location: number;
size: number;
}[];
}[];
tasks: {
description: string;
people: {
nickname: string;
}[];
}[];
}
我想定义一个可以接受这种类型的泛型函数,然后定义该类型的嵌套属性;例如,在这种情况下,这可能看起来像:
const houseSpecification = [{
name: 'houses',
children: [
// (not all subproperties of the type need to be defined, e.g. note how the
// 'tasks' branch is missing altogether)
{
name: 'rooms',
children: [
{
name: 'id',
},
],
},
{
name: 'doors',
},
],
}],
在每个分支中,'name' 属性 指定 属性 父对象的名称,它是一个 对象数组 类型。然后将数组中对象的类型作为 'children' 属性.
中条目的 'name' 的来源
我正在寻找对任何给定对象类型采用这种格式的某些函数中这种规范类型的定义,例如function myFunction<T extends object>(spec: Spec<T>[])
中 Spec
的类型使得 myFunction<TestUser>
将 houseSpecification
作为其参数。
我有一些我认为应该有用的东西,但由于某种原因似乎没有正确地递归:
// extracts the type of an array, e.g. ArrayType<({ id: string })[]> -> { id: string }
export type ArrayType<T> = T extends (infer U)[] ? U : never;
// gives a union type of all keys in an object that yield an array of objects,
// e.g. ObjectArrKeys<{ id: string, data: object[], users: object[] }> -> 'data' | 'users'
export type ObjectArrKeys<T> = {
[K in keyof T]: T[K] extends object[] ? K : never;
}[keyof T];
// used as `function myFunction<T extends object>(spec: Spec<T, ObjectArrKeys<T>>[])`
export type Spec<T extends object, Q extends ObjectArrKeys<T>> = {
name: Q;
children?: Spec<
ArrayType<T[Q]>,
ObjectArrKeys<ArrayType<T[Q]>>
>[]
}
我已经测试了两个实用程序,ArrayType
和 ObjectArrKeys
,它们似乎工作正常。然而,Typescript 似乎不喜欢 Spec
中的递归,抱怨 ArrayType<T[Q]>
与类型 object
不匹配,尽管事实上 Q
只能表示生成对象数组的 T
键。
有没有更简单的方法来获得我的最终结果?为什么 Typescript 不能正确推断这些类型并声称它不够具体?
谢谢。
如果我正确理解了问题,这应该可以解决问题:
type Spec<T> = {
[key in ObjectArrKeys<T>]: {
name: key, children?: T[key] extends (infer I)[] ? Spec<I> : never
}
}[ObjectArrKeys<T>][]
首先,由于houseSpecification
和嵌套的children
属性都是数组,所以我也让Spec
return为数组类型。我遍历所有具有数组属性的键,并构建所有可能的 name
和 children
组合的并集。对于每次迭代,我然后采用推断的元素类型并递归调用 Spec
.
在将嵌套对象传递到递归 Spec
调用之前,我再次检查 T[key]
是否确实 extends (infer I)[]
。我认为这些信息之前丢失了,TypeScript 并不知道 T[key]
是 any[]
类型,即使 ObjectArrKeys
过滤了所有数组键。
假设我有一个嵌套对象类型来定义,比方说,一个用户:
type TestUser = {
name: string;
email: string;
houses: {
address: string;
rooms: {
floor: number;
color: string;
connectedTo: {
id: number;
}[];
}[];
doors: {
location: number;
size: number;
}[];
}[];
tasks: {
description: string;
people: {
nickname: string;
}[];
}[];
}
我想定义一个可以接受这种类型的泛型函数,然后定义该类型的嵌套属性;例如,在这种情况下,这可能看起来像:
const houseSpecification = [{
name: 'houses',
children: [
// (not all subproperties of the type need to be defined, e.g. note how the
// 'tasks' branch is missing altogether)
{
name: 'rooms',
children: [
{
name: 'id',
},
],
},
{
name: 'doors',
},
],
}],
在每个分支中,'name' 属性 指定 属性 父对象的名称,它是一个 对象数组 类型。然后将数组中对象的类型作为 'children' 属性.
中条目的 'name' 的来源我正在寻找对任何给定对象类型采用这种格式的某些函数中这种规范类型的定义,例如function myFunction<T extends object>(spec: Spec<T>[])
中 Spec
的类型使得 myFunction<TestUser>
将 houseSpecification
作为其参数。
我有一些我认为应该有用的东西,但由于某种原因似乎没有正确地递归:
// extracts the type of an array, e.g. ArrayType<({ id: string })[]> -> { id: string }
export type ArrayType<T> = T extends (infer U)[] ? U : never;
// gives a union type of all keys in an object that yield an array of objects,
// e.g. ObjectArrKeys<{ id: string, data: object[], users: object[] }> -> 'data' | 'users'
export type ObjectArrKeys<T> = {
[K in keyof T]: T[K] extends object[] ? K : never;
}[keyof T];
// used as `function myFunction<T extends object>(spec: Spec<T, ObjectArrKeys<T>>[])`
export type Spec<T extends object, Q extends ObjectArrKeys<T>> = {
name: Q;
children?: Spec<
ArrayType<T[Q]>,
ObjectArrKeys<ArrayType<T[Q]>>
>[]
}
我已经测试了两个实用程序,ArrayType
和 ObjectArrKeys
,它们似乎工作正常。然而,Typescript 似乎不喜欢 Spec
中的递归,抱怨 ArrayType<T[Q]>
与类型 object
不匹配,尽管事实上 Q
只能表示生成对象数组的 T
键。
有没有更简单的方法来获得我的最终结果?为什么 Typescript 不能正确推断这些类型并声称它不够具体?
谢谢。
如果我正确理解了问题,这应该可以解决问题:
type Spec<T> = {
[key in ObjectArrKeys<T>]: {
name: key, children?: T[key] extends (infer I)[] ? Spec<I> : never
}
}[ObjectArrKeys<T>][]
首先,由于houseSpecification
和嵌套的children
属性都是数组,所以我也让Spec
return为数组类型。我遍历所有具有数组属性的键,并构建所有可能的 name
和 children
组合的并集。对于每次迭代,我然后采用推断的元素类型并递归调用 Spec
.
在将嵌套对象传递到递归 Spec
调用之前,我再次检查 T[key]
是否确实 extends (infer I)[]
。我认为这些信息之前丢失了,TypeScript 并不知道 T[key]
是 any[]
类型,即使 ObjectArrKeys
过滤了所有数组键。