How to declare a type as a subset of another type?

Hi all I’m trying to model a condition:

type rec condition = AndGroup(list<condition>) | OrGroup(list<condition>) | Eq(string, string) | IsEmpty(string) | IsOneOf(string, list<string>)

let cond = AndGroup(list{
  Eq("1", "1"),
  IsOneOf("aaa", list{"x", "bb", "aaa"})
 })

I want to write two React components, one for rendering AndGroup and OrGroup, the other for rendering a simple condition(Eq,IsEmpty, IsOneOf).
I come from TypeScript, in TS I might write:

interface GroupProps {
  cond: AndGroup | OrGroup
}

interface ExprProps {
  cond: Eq | IsEmpty | IsOneOf
}

I’m hoping to achieve something like this in ReScript:

type cond1 = condition.AndGroup | condition.OrGroup

I’m wondering, is the way I’m modeling the condition correct? If it is correct, what syntax should I use in ReScript?

If you want to combine variant types, take a look at polymorphic variants in the manual, they explain how to do it, basically they’re structural variants and allow you do this:

type red = [#Ruby | #Redwood | #Rust]
type blue = [#Sapphire | #Neon | #Navy]

// Contains all constructors of red and blue.
// Also adds #Papayawhip
type color = [red | blue | #Papayawhip]

But for your use case, this is not going to work well because your type is recursive, I think you’ll have to create mutually recursive modules to have react components that can reference themselves, the downside of this solution is that you have to manually define the signature of these modules which makes it a bit verbose but is definitely doable, take a look at the example in the playground.

I recently asked a similar question regarding union types from TypeScript. Here is the solution I used. Hope it might help you.

So for your TypeScript type declaration:

type cond1 = condition.AndGroup | condition.OrGroup

the equivalent ReScript code will be:

type andGroup
type orGroup
type cond1
external makeCondAnd: andGroup => cond1 = "%identity"
external makeCondOr: orGroup => cond1 = "%identity"

And you should be able to convert the types from andGroup to cond1 using these make functions.

Do note that we will get untagged unions in the upcoming ReScript v11. It will greatly ease expressing TypeScript union types in ReScript.