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.

Recursive Types Cannot be Defined

See original GitHub issue

I might have a Typescript type like this:

type T = string | T[]

But if I try to define this type in valita I cannot pass the identifier to its own instantiator:

const T = v.union(v.string(), v.array(T)); // error: identifier used before it is defined

I mulled over this a bit, but I can’t think of a smart way to implement it that doesn’t involve somehow the union after it is instantiated, and then having to trick typescript into giving it a different type…

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:7 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
Bubz43commented, Sep 17, 2021

I’m using Valita quite heavily in a not yet public rework of that project with plenty of v.optionals and I didn’t have to change anything, so it shouldn’t be too breaking.

2reactions
jviidecommented, Sep 17, 2021

Good discussion! Yes, recursive types are indeed something that we ourselves have needed for some time now. So I added lazy to the library, it works quite similarly to @Bubz43’s suggestion with some additional guardrails:

type T = string | T[];
const t: v.Type<T> = v.lazy(() => v.union(v.string(), v.array(t)));

The main problem here was trying to solve was the following scenario:

type T = string | T[];
const t: v.Type<T> = v.lazy(() => v.union(v.string(), v.array(t)).optional());

// Uh oh, t's optionality is erased:
const o = v.object({ t });
type X = v.Infer<typeof o>; // { t: T }, should be { t?: T }

So I took some drastic measures and restricted where .optional() types can be used! 🙂 For example, you now can’t return an optional from lazy, so this is a type error:

const t: v.Type<T> = v.lazy(() => v.union(v.string(), v.array(t)).optional());

As is this:

const t: v.Type<T> = v.lazy(() => v.union(v.string(), v.array(t))).optional();

The most common usecase for .optional() is still supported:

type T = string | T[];
const t: v.Type<T> = v.lazy(() => v.union(v.string(), v.array(t)));

const o = t.object({
  x: t.optional()
});

I believe this a pretty good tradeoff between expressivity and providing safe guardrails against accidents. This is a backwards incompatible change, for which I apologize. Looking at the only public repository using Valita, @Bubz43’s https://github.com/Bubz43/ep2e, it seems that no changes are needed there at least 🙂

Read more comments on GitHub >

github_iconTop Results From Across the Web

CS 3110 Lecture 4 Variant types and polymorphism
This type has two constructors, Nil and Cons . It is a recursive type because it mentions itself in its own definition (in...
Read more >
How can I make a recursive Python type defined over several ...
Inlining the individual types will give you infinitely long type definitions, as it's recursive. My recursive JsonType works fine in pyright.
Read more >
4.6 Recursive Types
Even though recursive types do not admit a logical interpretation as propo- sitions, we can still define a term calculus using introduction and...
Read more >
recursive type definitions · Issue #3496 · microsoft/TypeScript
I have a recursive type definition for JSON Serializable entities (Exhibit A, edited after discussion with @JsonFreeman ): export type ...
Read more >
Reading 16, Part 1: Recursive Data Types
This is a recursive definition of ImList as a set of values. Read it like this: the set ImList consists of values formed...
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 Reddit Thread

No results found

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