question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Support for nested/recursive types?

See original GitHub issue

Hi there,

this library looks amazing and seems like what i am currently missing in native typescript. But there is one thing, i hadn’t success to achieve with this library: nested recursive types. I need to define the structure types for an object literal like:

type item = {
  Prop1: string,
  Prop2: number
}

type group = {
  Prop3: string,
  Items: Array<item | group>
}

const JSON: group = {
  Prop3: "Root",
  Items: [
    {
      Prop1: "Item 1",
      Prop2: 123
    },
    {
      Prop3: "Nested Group 1",
      Items: [
        /*
          ... and so on
        */
      ]
    }
  ]
}

If i try to achieve this with runtypes the following way:

const item = Record({
  Prop1: String,
  Prop2: Number
});

const group = Record({
  Prop3: String,
  Items: Array(Union(item, group))
});

it gives a compiler error “block-scoped variable ‘group’ is used before its declaration”. If i replace const group with var group the compiler error disappears but typescript recognizes group only as type any…

Is there any way to describe the desired structure? Thanks for any hint on this…

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:1
  • Comments:10 (5 by maintainers)

github_iconTop GitHub Comments

3reactions
pelotomcommented, Jun 11, 2017

Unfortunately type inference is not possible when using Lazy to make recursive types. You need to help out the compiler a little:

const item = Record({
  Prop1: String,
  Prop2: Number
});

type Group = { Prop3: string, Items: (Static<typeof item> | Group)[] }
const group: Runtype<Group> = Lazy(() => Record({
  Prop3: String,
  Items: Array(Union(item, group))
}));

But as long as you have noImplicitAny enabled (which you always should 😃), it will be a static type error if you fail to do this, or if you do it incorrectly. For instance, if you fail to provide the annotation:

const group = Lazy(() => Record({
//    ^^^^^
// 'group' implicitly has type 'any' because it does not have a type annotation and is referenced directly or indirectly in its own initializer

And if you get the annotation wrong:

type Group = { Propp3: string, Items: (Static<typeof item> | Group)[] }
const group: Runtype<Group> = Lazy(() => Record({
//    ^^^^^
// Type 'Record<{ Prop3: String; Items: Arr<Union2<Record<{ Prop1: String; Prop2: Number; }>, Runtype<Grou...' is not assignable to type 'Runtype<Group>'.
//  Types of property 'check' are incompatible.
//    Type '(x: any) => { Prop3: string; Items: (any | Group)[]; }' is not assignable to type '(x: any) => Group'.
//      Type '{ Prop3: string; Items: (any | Group)[]; }' is not assignable to type 'Group'.
//        Property 'Propp3' is missing in type '{ Prop3: string; Items: (any | Group)[]; }'.

So type checking still works fine, just not type inference.

1reaction
pelotomcommented, May 31, 2017

Hi, glad this library is useful to you! In order to implement a recursive type you need to use the Lazy combinator, like so:

const item = Record({
  Prop1: String,
  Prop2: Number
});

const group = Lazy(() => Record({
  Prop3: String,
  Items: Array(Union(item, group))
}));

This defers evaluation of the type definition until its first use, at which point the group variable will be in scope and the knot can be tied. Hope that helps!

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to Create Deep Recursive Types
Step 1. Put recursive instantiation into an object property · Step 2. Peel nested object type in a logarithmic order.
Read more >
Nested recursive Type Hinting in TypeScript?
You need to force the type cast, try this: <Route path={(Routes.user.invoices as RoutingVariants).get} exact > <GetInvoice /> </Route>.
Read more >
Types of Recursions
Recursion are mainly of two types depending on whether a function calls itself from within itself or more than one function call one...
Read more >
Do we need nested datatypes? - UPenn CIS
At first, nested datatypes don't seem all that different from regular datatypes. For example, even though the NTree type uses nested recursion, ...
Read more >
Recursive data structure
What if you want to put a limit on a number of nested children? ... If you wonder, how to define recursive type...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found