Search code examples
reactjstypescriptnext.jsheadless-ui

How to specify types in TypeScript?


I am trying to use the code example below in Next.js 15 (TypeScript), but getting the error on the line onChange={setSelectedPerson} and would like to know how to specify the types on passing:

Type error: Type 'Dispatch<SetStateAction<{ id: number; name: string; }>>' is not assignable to type '(value: NoInfer<{ id: number; name: string; }> | null) => void'.
  Types of parameters 'value' and 'value' are incompatible.
    Type 'NoInfer<{ id: number; name: string; }> | null' is not assignable to type 'SetStateAction<{ id: number; name: string; }>'.
      Type 'null' is not assignable to type 'SetStateAction<{ id: number; name: string; }>'.
import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react'
import { useState } from 'react'

const people = [
  { id: 1, name: 'Durward Reynolds' },
  { id: 2, name: 'Kenton Towne' },
  { id: 3, name: 'Therese Wunsch' },
  { id: 4, name: 'Benedict Kessler' },
  { id: 5, name: 'Katelyn Rohan' },
]

function Example() {
  const [selectedPerson, setSelectedPerson] = useState(people[0])
  const [query, setQuery] = useState('')

  const filteredPeople =
    query === ''
      ? people
      : people.filter((person) => {
          return person.name.toLowerCase().includes(query.toLowerCase())
        })

  return (
    <Combobox value={selectedPerson} onChange={setSelectedPerson} onClose={() => setQuery('')}>
      <ComboboxInput
        aria-label="Assignee"
        displayValue={(person) => person?.name}
        onChange={(event) => setQuery(event.target.value)}
      />
      <ComboboxOptions anchor="bottom" className="border empty:invisible">
        {filteredPeople.map((person) => (
          <ComboboxOption key={person.id} value={person} className="data-[focus]:bg-blue-100">
            {person.name}
          </ComboboxOption>
        ))}
      </ComboboxOptions>
    </Combobox>
  )
}

Solution

  • It looks like your useState for selectedPerson infers the type of people[0] which is Person.

    const [selectedPerson, setSelectedPerson] = useState(people[0])
    

    The typescript error is saying that the function you pass to onChange should have an argument with a nullish value, so you can either adjust the type of selectedPerson to include null or you can choose to do something else when you get null back from the onChange.

    Adding null to the selectedPerson type

    const [selectedPerson, setSelectedPerson] = useState<Person | null>(people[0])
    

    As an example, defaulting to the original value on null

    <Combobox 
      value={selectedPerson}
      onChange={
        (value) => {
          if (value) {
            setSelectedPerson(value);
          } else {
            setSelectedPerson(people[0]);
          }
        }
      } 
      onClose={() => setQuery('')}>