具有特定深度的 TypeScript 递归类型

标签 typescript recursion types

TypeScript 允许您组合递归类型,但无法深入了解代码在较低级别(即深度)中的变化情况。例如,下面的代码在所有级别都具有相同类型的签名,我们必须在每个级别手动检查是否存在 sub属性(property)。

type Recurse = { foo: string; sub?: Recurse }

function recurse(depth: number): Recurse {
  if (depth === 0) return { foo: 'hey' }
  return {
    foo: 'hey',
    sub: recurse(depth - 1),
  }
}
const qux = recurse(5)

我正在寻找的是一个类型签名,它可以为我们提供函数在特定深度返回什么的具体证据。

const qux0: { foo: string } = recurse(0)
const qux1: { foo: string, sub: { foo: string } } = recurse(1)
const qux2: { foo: string, sub: {  foo: string, sub: { foo: string }} } = recurse(2)

这样,我们就不必在每个级别检查 sub属性,因为类型签名已经打包了该信息。

我有一种感觉,这可能可以通过条件类型实现,但没有具体证据。

你知道我怎么能做到这一点吗?

最佳答案

我认为您可能可以使用递归条件类型获得一些东西,但我建议不要使用这样的解决方案。毕竟,如果有人要调用 recurse(5000)返回类型会很大。

您可以轻松构建基于映射类型的解决方案,您可以在其中添加最多特定深度的子项类型:

type Recurse<T extends number =  number> = {
  foo: string;
  sub: RecurseChildren extends Record<T, infer C> ? C : Recurse
}

interface RecurseChildren {
  0: undefined;
  1: Recurse<0>
  2: Recurse<1>
  3: Recurse<2>
  4: Recurse<3>
  5: Recurse<4>
  6: Recurse<5>
  7: Recurse<6>
  8: Recurse<7>
  9: Recurse<8>
  10: Recurse<9>
}


function recurse<T extends number>(depth: T): Recurse<T> {
  if (depth === 0) return { foo: 'hey', sub: undefined as any }
  return {
    foo: 'hey',
    sub: recurse(depth - 1) as any,
  }
}
const qux = recurse(5)

qux.sub.sub.sub.sub.sub.sub // last one is undefined 

Playground Link

关于具有特定深度的 TypeScript 递归类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60168740/

相关文章:

javascript - 如何在 Angular 构造函数之外提供服务?

node.js - 无法使用 typescript 导入 Node 类型的模块

angular - 如何让 Leaflet Marker-Cluster Freezable 方法显示在 VS Code IntelliSense 中

javascript - typescript - 删除毫秒

parsing - 如何在 Rust 中为我自己的解析器编写组合器?

java - 将一个数 n 分成两个数,使得两个数之和为 n

c++ - 不使用 vector 、大小或其他参数的递归回文检查

recursion - 无法将递归构建的列表返回到 Lisp 中的调用函数

reactjs - 无法分配给 'state',因为它是常量或只读属性

c++ - 类型不匹配