【问题标题】: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 类型的索引对数组进行索引;这就像对对象进行索引以获取属性(因为数组只是对象)。如果一切都满足您的需求,我会写一个答案来解释这一点。 (顺便说一句,可能是一两个小时后)
  • 是的,这完全是我想要的!不急。非常感谢

标签: typescript graphql relay


【解决方案1】:

从概念上讲,您想深入了解ProductAutoSuggestQueryResponseindex 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} | undefined{a: string} | null{a: 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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-11-16
    • 2022-01-08
    • 1970-01-01
    • 2023-01-13
    • 1970-01-01
    • 2018-04-17
    • 2019-09-06
    • 2017-01-08
    相关资源
    最近更新 更多