如何创建通用类型组件来使用React Native的FlatList或SectionList?

问题描述 投票:0回答:1

描述

我正在尝试创建一个自定义

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>
    );

错误

错误#1

如代码中所述,从

sections
析构
props
会引发以下错误:

Property 'sections' does not exist on type 'Readonly<ListProps<listT, any>>'.ts(2339)

错误#2

定义

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
并为其分配了一些事件处理程序。任何其他更好的方法来实现此功能都可以是一个很好的答案。

reactjs typescript list react-native typescript-generics
1个回答
0
投票
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} />;
};
© www.soinside.com 2019 - 2024. All rights reserved.