我正在尝试创建一个自定义
ManagedList
组件,该组件将具有 props
类型,其类型为 FlatListProps<itemT>
或 SectionListProps<itemT, SectionT = DefaultSectionT>
以及附加 { listType: ListType; dismissKeyboardOnPress?: boolean; dismissElevatedUIElements?: boolean;
属性。
为此,我创建了自定义类型
ListType
和 ListProps
:
type ListType = 'flat' | 'section';
type ListProps<listT extends ListType, itemT> = (
listT extends 'flat'
? FlatListProps<itemT>
: SectionListProps<itemT>
) & {
listType: ListType;
dismissKeyboardOnPress?: boolean;
dismissElevatedUIElements?: boolean;
};
然后我创建了一个接受通用参数的功能组件
listT extends ListType
,如下所示:
function ManagedList<listT extends ListType>(
props: Readonly<ListProps<listT, any>>
) {
const {
listType,
dismissKeyboardOnPress,
dismissElevatedUIElements,
data,
sections, // destructing sections throws error #1
renderItem,
...otherProps
} = props;
...
let listCmp;
if (listType === 'flat') {
listCmp = (
<FlatList
data={data}
renderItem={renderItem} // defining renderItem prop throws error #2
onTouchStart={touchStartHandler}
onLayout={layoutHandler}
onContentSizeChange={contentSizeChangeHandler}
onScroll={scrollHandler}
showsVerticalScrollIndicator={false}
{...otherProps}
/>
);
} else {
listCmp = (
<SectionList
sections={sections}
renderItem={renderItem} // defining renderItem prop throws error #2
onTouchStart={touchStartHandler}
onLayout={layoutHandler}
onContentSizeChange={contentSizeChangeHandler}
onScroll={scrollHandler}
showsVerticalScrollIndicator={false}
{...otherProps}
/>
);
}
return (
<View style={styles.listContainer}>
{listCmp}
{contentHeight > containerHeight && (
<Fragment>
<View style={styles.scrollbarTrack} />
<Animated.View
style={[styles.scrollbarThumb, animatedSyles]}
/>
</Fragment>
)}
</View>
);
如代码中所述,从
sections
析构 props
会引发以下错误:
Property 'sections' does not exist on type 'Readonly<ListProps<listT, any>>'.ts(2339)
renderItem
道具时会引发第二个错误。我相信这是因为
FlatList
和 SectionList
具有不同的 renderItem
定义/类型。 FlatList
的 renderItem
属性具有以下类型:
renderItem({
item: ItemT,
index: number,
separators: {
highlight: () => void;
unhighlight: () => void;
updateProps: (select: 'leading' | 'trailing', newProps: any) => void;
}
}): JSX.Element;
和
SectionList
的renderItem
道具类型:
renderItem({
item: ItemT,
index: number,
section: object, // <--- This is different
separators: {
highlight: () => void;
unhighlight: () => void;
updateProps: (select: 'leading' | 'trailing', newProps: any) => void;
}
}): JSX.Element;
为了解决错误#1,我尝试使用类型保护:
const {
listType,
dismissKeyboardOnPress,
dismissElevatedUIElements,
data,
renderItem,
...otherProps
} = props;
let sections;
if(props.sections) {
sections = props.section;
}
// or
const sections = props?.section ?? undefined;
但是所有这些 Type Guard 尝试都显示了类似的错误,因为
sections
不存在于 props
对象中。
我不确定如何解决错误#2。
注意:我想要完成的是有一个自定义组件来使用
FlatList
或 SectionList
并为其分配了一些事件处理程序。任何其他更好的方法来实现此功能都可以是一个很好的答案。
type ListType = 'flat' | 'section';
type fListProps<T> = FlatListProps<T> & {listType:'flat'}
type sListProps<T> = SectionListProps<T> & {listType:'section'}
type ListProps<T> = fListProps<T> | sListProps<T>
function MyList <T>(props: ListProps<T>) {
// no ts errors here
if (props.listType == 'flat') {
return <FlatList {...props} />;
}
// no ts errors here
return <SectionList {...props} />;
};