Custom components library development using TypeScript

Hey there. I am developing a custom component library for Retool using TypeScript. If there is a way to add data type to Retool.useStateObject hook?

For example I have a data contract like this:

interface IListItem {
id: number;
name: string;
description: string;
}

How can I expose an object state value to Retool using this type with Retool.useStateObject<IListItem>(), or is there a preferred way to do this in the current API?

Hey @MChuduk, welcome to the Retool Community!

I recommend checking out the Retool Custom Component documentation β€” a great resource.

1 Like

Hey, tanks for reply. I checked the documentation as well, but I can't realize why Retool.useStateObject is not a generic for some reason.

I used a workaround to solve this problem, but I'm not sure that's better way to do that:

  const [item] = Retool.useStateObject({
    name: 'item'
  }) as unknown as [IlistItem, (value: IlistItem) => void]

Hey @MChuduk ,

You might consider using the following approach to expose an object state value:

const [state, setState] = Retool.useStateObject<IListItem>({
    name: 'listItem',
    initialValue: { id: 0, name: '', description: '' },
    inspector: 'text',
    description: 'A list item state',
    label: 'List Item',
  });
1 Like

Maybe I'm confusing something. But Retool.useStateObject is not a generic function according to definition:

     function useStateObject({
      name,
      initialValue,
      inspector,
      description,
      label,
    }: {
      name: string
      initialValue?: SerializableObject
      inspector?: 'text' | 'hidden'
      description?: string
      label?: string
    }): readonly [SerializableObject, (newValue: SerializableObject) => void]

It means that I can't provide an object type using <> brackets.

Hey @MChuduk

Apologies for the confusion earlier β€” that was my oversight in not fully understanding the issue.

The Retool SDK doesn’t support generics directly with useStateObject. However, we can safely cast the result as a tuple with the appropriate types, as shown below:

import { type FC, useEffect } from 'react'
import { Retool } from '@tryretool/custom-component-support'

interface IListItem {
  id: number
  name: string
  description: string
}

export const DemoStateObject: FC = () => {
  const [item, setItem] = Retool.useStateObject({ name: 'selectedItem' }) as [
    IListItem,
    (val: IListItem) => void
  ]

  useEffect(() => {
    console.log('Selected item from Retool:', item)

    // Optional: set a new object to sync back to Retool
    setItem({
      id: 1,
      name: 'Sample Item',
      description: 'This is a sample description'
    })
  }, [])

  return (
    <div>
       <h1>{item?.id}</h1>
      <h2>{item?.name}</h2>
      <p>{item?.description}</p>
    </div>
  )
}

In Retool, create a temporary state variable called selectedItem and initialize it with an object like this:


{
  "id": 101,
  "name": "Test Item",
  "description": "Test description here"
}

2 Likes

Well, there is only one way how to handle it at the moment. Thanks for suggestion.