嵌套对象类型解构

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&lt;&gt;,但它似乎变得非常复杂,并且数组导致了我的问题。

【问题讨论】:

你有两个名为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 的类型为类型 numbers 的类型为 'node'。这样的索引可以通过索引访问类型在类型级别完成:

type NodeType =
  ProductAutoSuggestQueryResponse['node']['products']['edges'][number]['node'];
/* type NodeType = 
    name: string;
    id: string;
    currencies: readonly string[];
 */

这是你想要的。


那太好了。不幸的是,您的 ProductAutoSuggestQueryResponse 类型与我上面写的不完全一样。在通过对象结构的各个级别,有optional 或其他nullable 属性,这意味着它们可以包括undefinednull。不是a: string,而是a: string | undefineda: string | nulla: string | undefined | null。你不能安全地索引到可能是undefinednull 的东西,所以编译器不会让你直接使用indexed access types。

可以做的是使用the NonNullable&lt;T&gt; 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&lt;T&gt;。否则,我们获取第一个键 KF 并使用 KF 索引到 NonNullable&lt;T&gt;,并获取新类型和键元组的其余部分 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

【讨论】:

以上是关于嵌套对象类型解构的主要内容,如果未能解决你的问题,请参考以下文章

对象解构中的类型

对象解构中的类型

嵌套对象和数组解构

ES6解构嵌套对象

ES6解构嵌套对象

JS基础 对象