gpt4 book ai didi

typescript - 在 TypeScript 中获取递归属性的联合类型

转载 作者:行者123 更新时间:2023-12-04 13:35:04 25 4
gpt4 key购买 nike

假设我们有这样的接口(interface):

interface Node<C extends Node[] = any[]> {
children: C
}
这里,C 是一个泛型,它是一个元组,它是这个节点的子节点的类型。
让我们定义一些节点:
type Foo = Node<[]>
type Bar = Node<[Foo, Foo]>
type Baz = Node<[Bar]>
Baz 是根节点。它是一个 Bar 节点的父节点,它是两个 Foo 节点的父节点。福没有 child 。
如果我想获得一个节点的 child ,我可以这样做:
type TupleOfNodeChildren<N extends Node> = N['children'];
以下是此 TupleOfNodeChildren 的一些示例类型,按预期工作:
type T0 = TupleOfNodeChildren<Foo> // []
type T1 = TupleOfNodeChildren<Bar> // [Foo, Foo]
type T3 = TupleOfNodeChildren<Baz> // [Bar]
现在假设我想要一个类型,它是元组中每个不同类型的联合。我可以:
type TypesOfNodeChildren<N extends Node> = TupleOfNodeChildren<N>[number];
然后当然是我们的例子:
type T10 = TypesOfNodeChildren<Foo> // never
type T11 = TypesOfNodeChildren<Bar> // Foo
type T12 = TypesOfNodeChildren<Baz> // Bar
所有这些都很好用。但是如果我想要一个叫做 TypesOfAllChildren 的东西怎么办? ,就像 TypesOfNodeChildren ,但它不仅仅是直系子节点的联合,而是 的联合。全部 节点的 child ?
这是它的工作方式:
type T20 = TypesOfAllChildren<Foo> // never
type T21 = TypesOfAllChildren<Bar> // Foo
type T22 = TypesOfAllChildren<Baz> // Bar | Foo <--- Includes types of deep children
请注意 T22有 Bar,Baz 的直接子代,还有 Foo,它是 Bar 的子代。
我似乎无法得到这个 TypesOfAllChildren键入工作;无论我尝试什么,它都会不断提示循环引用。我假设您需要某种递归来获取所有 child 的类型,但我不确定如何在没有 TypeScript 提示的情况下实现它。 Here is a playground with these types and examples.
编辑 :
这是我尝试过的示例:
type TypesOfAllChildren<N extends Node> = TypesOfNodeChildren<N> | TypesOfAllChildren<TypesOfNodeChildren<N>>;
// ~~~~~~~~~~~~~~~~~~ Recursively references itself
通过条件类型添加退出条件也不起作用:
type TypesOfAllChildren<N extends Node> = TypesOfNodeChildren<N> | (TypesOfNodeChildren<N> extends never ? never : TypesOfAllChildren<TypesOfNodeChildren<N>>);

最佳答案

我解决了。所以我们有:

interface Node<C extends Node[] = any[]> {
children: C
}

type Foo = Node<[]>
type Bar = Node<[Foo, Foo]>
type Baz = Node<[Bar]>
type Faz = Node<[Baz]>
并且想要一种可以得到所有子节点的联合的类型,在树的任何地方。我发现这有效:
type SelfAndAllChildren<N extends Node> = N['children'][number] extends never ? N : {
// @ts-ignore
getSelfAndChildren: N | SelfAndAllChildren<N['children'][number]>
}[N extends never ? never : 'getSelfAndChildren']
好的,那么首先:
  • 有一个条件检查 child 的类型是否为 never , IE。该节点没有任何 child 。如果是这样,那么我们只需返回 N并完成。
  • 如果有 child ,那么首先我们创建一个包含 getSelfAndChildren 的类型。 .我们需要这样做是因为只允许属性的类型递归地引用它们自己——联合类型不能。
  • getSelfAndChildren属性将包括节点本身,N ,然后是 SelfAndAllChildren节点的子节点。这是对 SelfAndAllChildren 的递归引用,但因为它在 getSelfAndChildren 上属性,TypeScript 不会提示。
  • 最后,我们需要实际获取 getSelfAndChildren 的类型属性(property)。不幸的是,TypeScript 会提示递归引用 除非我们使用条件类型 使用 getSelfAndChildren 索引接口(interface)在里面。所以,我们输入了一个条件,它总是返回 getSelfAndChildren 的类型。 -- 它本身具有对 SelfAndAllChildren 的递归引用.
  • 请注意 @ts-ignore上方getSelfAndChildren .如果我们传入 anySelfAndAllChildren ,那会抛出错误。把@ts-ignore消除 any 上的错误, 类型默认为 any ,这就是我们想要的。

  • 请注意这是 "not recommended"因为它可能会影响性能。
    另外,这里有一个类型 刚拿到 child 如果您正在寻找:
    type JustAllChildren<N extends Node> = SelfAndAllChildren<N['children'][number]>
    然后 here is a playground一切。

    关于typescript - 在 TypeScript 中获取递归属性的联合类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62632538/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com