我一直在努力解决这个组件的打字问题。它需要是通用的,但我似乎无法使它工作:
import { clsx } from 'clsx';
import { useCombobox } from 'downshift';
import type { ForwardedRef, ReactNode } from 'react';
import { forwardRef } from 'react';
import { Input } from '../../atoms/Input/Input';
import './Combobox.css';
import { ComboboxProvider } from './ComboboxContext';
import { ComboboxList } from './ComboboxList';
import { ComboboxListItem } from './ComboboxListItem';
import type { ComboboxProps } from './types';
/**
* ComboBox
*
* @description A component with a dropdown, search and filter functionality
*
* @example
* <Combobox>
* <Combobox.Prefix>
* <Search />
* </Combobox.Prefix>
* <Combobox.List>
* <Combobox.Item>
* <Item />
* </Combobox.Item>
* <Combobox.Item>
* <Item />
* </Combobox.Item>
* <Combobox.Item>
* <Item />
* </Combobox.Item>
* <Combobox.Item>
* <Item />
* </Combobox.Item>
* </Combobox.List>
* <Combobox.Suffix>
* <Close />
* </Combobox.Suffix>
* </Combobox>
*/
const Combobox = forwardRef(
<Item,>(
{ placeholder, name, id, defaultValue, className, children, ...props }: ComboboxProps<Item>,
ref: ForwardedRef<HTMLInputElement>,
) => {
const { getInputProps, ...rest } = useCombobox<Item>(props);
return (
<Input
{...getInputProps({ name, id, placeholder, defaultValue, ref })}
className={clsx('combobox', className)}
>
<ComboboxProvider {...rest}>{children}</ComboboxProvider>
</Input>
);
},
);
const CompoundCombobox = <Item,>() =>
Object.assign(Combobox<Item>, {
Prefix: Input.Prefix,
Suffix: Input.Suffix,
List: ComboboxList,
Item: ComboboxListItem,
});
export { CompoundCombobox as Combobox };
这会在该行上产生以下错误(更具体地说是在通用错误上):
Object.assign(Combobox<Item>, {
类型“ForwardRefExoticComponent
& UseComboboxProps & RefAttributes>”没有适用类型参数列表的签名。
这些是 ComboboxProps:
type ComboboxProps<Item> = Pick<
InputProps,
'className' | 'children' | 'placeholder' | 'defaultValue' | 'name' | 'id'
> &
UseComboboxProps<Item>;
我希望能够像这样使用它:
<Combobox<ComboboxItemType>
items={items}
placeholder="Combobox"
id="combobox"
name="combobox"
itemToString={itemToString}
onInputValueChange={({ inputValue }) => {
items.filter((el) => filter(el, inputValue));
}}
>
<Combobox.Prefix>
<Search />
</Combobox.Prefix>
<Combobox.List>
{items.map((item, index) => (
<Combobox.Item key={index} index={index} item={item}>
<div
style={{
display: 'flex',
flexDirection: 'row',
justifyContent: 'space-between',
width: '100%',
}}
>
<span>{item.title}</span>
<span style={{ color: 'var(--neutral-800)' }}>{item.category}</span>
</div>
</Combobox.Item>
))}
</Combobox.List>
</Combobox>
两个最重要的问题:
forwardRef
变得通用是出了名的烦人,你必须跳舞才能让它发挥作用。请参阅此答案。CompoundCombobox
不必要是一个函数。您只想将这些属性添加到组件上,不需要函数包装器。您还引用了类型 Combobox<Item>
作为 Object.assign
第一个参数中的值。你只想要 Combobox
在那里。type ComboboxType = <Item>(
props: ComboboxProps<Item> & React.RefAttributes<HTMLInputElement>,
) => React.ReactElement | null;
const Combobox: ComboboxType = forwardRef((props, ref) => {
const { placeholder, name, id, defaultValue, className, children, ...rest } =
props;
const { getInputProps, ...others } = useCombobox<Item>(props);
return (
<Input
{...getInputProps({ name, id, placeholder, defaultValue, ref })}
className={clsx("combobox", className)}
>
<ComboboxProvider {...others}>{children}</ComboboxProvider>
</Input>
);
});
const CompoundCombobox = Object.assign(Combobox, {
Prefix: Input.Prefix,
Suffix: Input.Suffix,
List: ComboboxList,
Item: ComboboxListItem,
});
export { CompoundCombobox as Combobox };