Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript recursive type with particular depth

TypeScript allows you to compose recursive types but gives no insight into how the code changes in lower levels (i.e. depths). The code below, for example, would have the same kind of signature across all levels, and we would have to manually check at each level that there exists a 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)

What I am seeking is a type signature that would give us concrete evidence of what the function returned at a particular depth.

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)

This way, we would not have to check at every level for the sub property as the type signature already packs that information.

I have a feeling that this might be possible to achieve with conditional types but have no concrete evidence.

Do you have any idea how I could achieve that?

like image 489
maticzav Avatar asked Feb 11 '20 12:02

maticzav


People also ask

How do you limit the depth of recursion?

The recursion depth limit in Python is by default 1000 . You can change it using sys. setrecursionlimit() function.

What is recursive depth?

Abstract. The maximum depth of recursion refers to the number of levels of activation of a procedure which exist during the deepest call of the procedure.

What is a recursive partial?

partial recursive function A function on the natural numbers that can be obtained from certain initial functions by a finite number of applications of composition, primitive recursion, and minimization.

What is the maximum depth of recursive calls?

The maximal recursion depth is limited by JavaScript engine. We can rely on it being 10000, some engines allow more, but 100000 is probably out of limit for the majority of them.


1 Answers

Until TS allows basic arithmetic operations for number types, you can use a decrement counter like Decr for all recursive types with particular depth:

type Decr = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] // add to a reasonable amount

type Recurse<N extends number> = N extends 0 ? 
  { foo: string } : 
  { foo: string; sub: Recurse<Decr[N]> }

function recurse<N extends number>(depth: N): Recurse<N> {
  if (depth === 0) return { foo: 'hey' } as Recurse<N>
  return {
    foo: 'hey',
    sub: recurse(depth - 1),
  } as Recurse<N>
}
type Decr9 = Decr[9] // 8

// compiles now
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)

Sample

like image 56
ford04 Avatar answered Oct 04 '22 20:10

ford04