Next.js 15(TypeScript)中如何为Combobox的onChange指定类型?
解决Next.js 15(TypeScript)中Headless UI Combobox onChange的类型不匹配问题
错误原因
Headless UI的Combobox组件onChange回调可能会传入null(比如用户清空选择场景),但你通过useState生成的setSelectedPerson只接受{ id: number; name: string }类型或(prev) => { id: number; name: string }函数,不兼容null类型,因此触发类型报错。
解决方案
方案1:修改状态类型,允许接收null
显式声明状态为Person | null类型,同时在组件中处理空值场景:
import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions } from '@headlessui/react' import { useState } from 'react' // 定义Person类型 type Person = { id: number; name: string } const people: Person[] = [ { 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() { // 声明状态允许为null const [selectedPerson, setSelectedPerson] = useState<Person | null>(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" // 处理null场景,返回默认文本 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> ) }
方案2:包装onChange回调,过滤null值
如果不想让状态接收null,可以包装一个回调函数,仅在传入值非空时更新状态:
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' }, ] // 提取类型 type Person = typeof people[number] function Example() { const [selectedPerson, setSelectedPerson] = useState(people[0]) const [query, setQuery] = useState('') // 包装回调,过滤null const handleComboboxChange = (value: Person | null) => { if (value !== null) { setSelectedPerson(value) } } const filteredPeople = query === '' ? people : people.filter((person) => { return person.name.toLowerCase().includes(query.toLowerCase()) }) return ( // 使用包装后的回调 <Combobox value={selectedPerson} onChange={handleComboboxChange} 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> ) }
内容的提问来源于stack exchange,提问作者Kinjo
相关产品推荐
相关产品推荐

