Colon type in @react.component external import

Looking at the documentation, what does @react.component(: confettiProps) in Import / Export ReactJS | React ?

: confettiProps is crucial for the jsx transform to work.
However, the docs do not at all explain why this is there.
So, does anybody know anything about this?

It’s specifying the type for the “props” argument in React by inserting it after props to have it explicitly typed. It’s useful together with external, the let-bound equivalent would be:

  @react.component
  let make = (~width: int, ~height: int) => {/*...*/}

We can’t specify labeled args in that manner in FFI components, so instead we need a way to type the props argument explicitly, hence @react.component(: <type>)

1 Like

as @xfcw explained, the “colon type” syntax allows to use a predefined type for the props type of a react component instead of using the labeled argument syntax.

Do note though that this syntax works both for external and let bindings and labeled arguments also work for externals.

This allows you to reuse the same type in multiple places of your code, for example if you receive the props of your component from a function, you can then directly destructure them:

module Confetti = {
  type confettiProps = {
    width: int,
    height: int,
  }

  @module("react-confetti") @react.component(: confettiProps)
  external make: confettiProps => React.element = "default"
}

let getConfettiProps = () => {Confetti.width: 300, height: 300}

@react.component
let make = () => {
  <Confetti {...getConfettiProps()} />
}

@nojaf what do you think would be missing from the docs?

From a syntactic perspective, this is quite baffling. The (: typeName) notation is unlike anything I’ve encountered so far. To the untrained eye, this may appear to be invalid syntax.

Where else can I use this? What does the combination of a colon and type signify? Why can it be used in an attribute?

Additionally, it’s rather strange why this is necessary, especially since the new @react.componentWithProps does not work. It feels somewhat disjointed, to be honest.