Type Parameters in nested modules

I’m attempting to write some bindings for Listbox in the @headlessui/react library (Headless UI – Unstyled, fully accessible UI components) and I’m curious if there’s a way to share a type parameter between a module and a nested module?

I have the following external bindings declared in Headless.res which I’ve shortened for brevity:

module Listbox = {
  @react.component @module("@headlessui/react")
  external make: (
    ~value: 'a,
    ~onChange: 'a => unit,
    ~children: React.element,
  ) => React.element = "Listbox"

  .....

  module Option = {
    @react.component @module("@headlessui/react") @scope("Listbox")
    external make: (~value: 'a,  ~children: React.element) => React.element = "Option"
  }
}

Is there anyway to ensure the type of the value prop in a child Listbox.Option is the same type used in value and onChange props in the parent Listbox? I don’t necessarily want to constrain what type can be used with the Listbox, just that the same type is used consistently.

2 Likes

Using module arguments might work for you.

module type ListboxType = {
  type t
}

module MakeListbox = (ListboxType: ListboxType) => {
  @react.component @module("@headlessui/react")
  external make: (
    ~value: ListboxType.t,
    ~onChange: ListboxType.t => unit,
    ~children: React.element,
  ) => React.element = "Listbox"

  module Option = {
    @react.component @module("@headlessui/react") @scope("Listbox")
    external make: (~value: ListboxType.t, ~children: React.element) => React.element = "Option"
  }
}

type person = {id: int}

module PersonListbox = MakeListbox({
  type t = person
})

And then use <PersonListbox /> and <PersonListbox.Option /> components.

Would that work?

1 Like

This is exactly what I was looking for, thank you!