嵌套对象类型解构
Posted
技术标签:
【中文标题】嵌套对象类型解构【英文标题】:Nest object type destructuring 【发布时间】:2022-01-22 03:56:44 【问题描述】:如何从嵌套对象中获取类型定义?
在这个例子中,我得到一个实体(产品)列表,我如何访问实体(节点)的类型定义。
这是使用relay-compiler
编译的
export type ProductAutoSuggestQueryResponse =
node:
products?:
edges: ReadonlyArray<
node:
name: string;
id: string;
currencies: ReadonlyArray<string> | null;
;
| null> | null;
| undefined;
| null;
;
我尝试过使用Pick<>
,但它似乎变得非常复杂,并且数组导致了我的问题。
【问题讨论】:
你有两个名为node
的属性,你想退出什么类型的? Is this what you want?。您需要将其推广到何种程度?还有其他我们需要关注的用例或边缘情况吗?
您可以编写一个递归类型函数来执行像this 这样的“不可为空的深度索引”,如果这是您想要的。告诉我。
@jcalz 在这种情况下,我试图获取第二个节点,但我有不同的查询,因此节点可能位于不同的深度。您发布的第二条评论看起来很棒。我假设我必须在到达数组时将number
放入路径中?
是的,要获取数组的元素类型,您可以使用number
类型的索引对数组进行索引;这就像对对象进行索引以获取属性(因为数组只是对象)。如果一切都满足您的需求,我会写一个答案来解释这一点。 (顺便说一句,可能是一两个小时后)
是的,这完全是我想要的!不急。非常感谢
【参考方案1】:
从概念上讲,您想深入了解ProductAutoSuggestQueryResponse
和index into it。让我们假设这种类型是:
type ProductAutoSuggestQueryResponse =
node:
products:
edges: readonly
node:
name: string;
id: string;
currencies: readonly string[];
;
[];
;
;
给定v
的修改版本ProductAutoSuggstQueryResponse
的值,您可以通过读取例如v.node.products.edges[0].node
来获得所需节点类型的值。更一般地,当p
的类型为'node'
且q
的类型为'products'
且r
的类型为'edges'
且i
的类型为类型 number
和 s
的类型为 'node'
。这样的索引可以通过索引访问类型在类型级别完成:
type NodeType =
ProductAutoSuggestQueryResponse['node']['products']['edges'][number]['node'];
/* type NodeType =
name: string;
id: string;
currencies: readonly string[];
*/
这是你想要的。
那太好了。不幸的是,您的 ProductAutoSuggestQueryResponse
类型与我上面写的不完全一样。在通过对象结构的各个级别,有optional 或其他null
able 属性,这意味着它们可以包括undefined
或null
。不是a: string
,而是a: string | undefined
或a: string | null
或a: string | undefined | null
。你不能安全地索引到可能是undefined
或null
的东西,所以编译器不会让你直接使用indexed access types。
您可以做的是使用the NonNullable<T>
utility type 将类似a: string | undefined | null
的内容转换为a: string
,然后再将其编入索引。这可以手动完成,但很烦人:
type NodeTypeManual = NonNullable<
NonNullable<
NonNullable<
NonNullable<
ProductAutoSuggestQueryResponse['node']
>['products']
>['edges']
>[number]
>['node']
/* type NodeTypeManual =
name: string;
id: string;
currencies: ReadonlyArray<string> | null;
*/
如果您发现要经常这样做,您可以编写一个递归的conditional type,对tuple 的索引进行操作:
type NonNullableDeepIndex<T, KT extends PropertyKey[]> =
KT extends [infer KF, ...infer KR] ? (
KF extends keyof NonNullable<T> ? (
NonNullableDeepIndex<NonNullable<T>[KF], Extract<KR, PropertyKey[]>>
) : never
) : NonNullable<T>;
类型函数NonNullableDeepIndex
接受一个类型T
和一个键元组KT
。如果键元组为空,我们只返回NonNullable<T>
。否则,我们获取第一个键 KF
并使用 KF
索引到 NonNullable<T>
,并获取新类型和键元组的其余部分 KR
,并递归评估 NonNullableDeepIndex
。
那么我们可以将NodeType
表达得少一点重复:
type NodeType = NonNullableDeepIndex<
ProductAutoSuggestQueryResponse,
["node", "products", "edges", number, "node"]
>;
/* type NodeType =
name: string;
id: string;
currencies: ReadonlyArray<string> | null;
*/
Playground link to code
【讨论】:
以上是关于嵌套对象类型解构的主要内容,如果未能解决你的问题,请参考以下文章