描述

我正在try 创建一个自定义的ManagedList组件,其中将有props,其中类型为FlatListProps<itemT>SectionListProps<itemT, SectionT = DefaultSectionT>,附加{ listType: ListType; dismissKeyboardOnPress?: boolean; dismissElevatedUIElements?: boolean;属性.

执行

为此,我创建了一个自定义类型ListTypeListProps:

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

正如代码中提到的,从props析构sections会引发以下错误:

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

错误#2

定义renderItem个props 时会抛出第二个错误.我相信这是因为FlatListSectionList有不同的renderItem个定义/类型.FlatList有以下类型的renderItem prop:

renderItem({
  item: ItemT,
  index: number,
  separators: {
    highlight: () => void;
    unhighlight: () => void;
    updateProps: (select: 'leading' | 'trailing', newProps: any) => void;
  }
}): JSX.Element;

SectionListrenderItemprops 类型:

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,我try 使用Type Guards:

const {
    listType,
    dismissKeyboardOnPress,
    dismissElevatedUIElements,
    data,
    renderItem,
    ...otherProps
} = props;
    
let sections;
if(props.sections) {
    sections = props.section;
}

// or

const sections = props?.section ?? undefined;

但是所有这些类型警卫try 都显示了类似的错误,因为sections不存在于props对象中.

我不知道怎么解决错误#2个问题.

NOTE:我试图实现的是有一个单独的自定义组件来使用FlatListSectionList,这些组件分配了一些事件处理程序.任何其他更好的方法来实现这个功能都是一个很好的答案.

推荐答案

type ListType = 'flat' | 'section';
type SharedListProps = {
  listType: ListType;
  dismissKeyboardOnPress:boolean;
  dismissElevatedUIElements:boolean;
};
type fListProps<T> = FlatListProps<T> & SharedListProps & {listType: 'flat'};
type sListProps<T> = SectionListProps<T> &
  SharedListProps & {listType: 'section'};
type ListProps<T> = fListProps<T> | sListProps<T>;


function MyList<T>(props: ListProps<T>) {
  const {
    listType,
    dismissKeyboardOnPress,
    dismissElevatedUIElements,
    renderItem,
    /*
    until listType value is checked typescript is unable to infer
    whether flatlist/sectionlist specific properties should exist
     */
    // data,
    // sections,
    ...otherProps
  } = props;

 
  if (props.listType == 'flat') {
    // access flatlist specific props here
    console.log(props.data);
    return <FlatList {...props} />;
  }
  // access section list specific props here
  console.log(props.sections);
  return <SectionList {...props} />;
}

Typescript相关问答推荐

如何根据参数的值缩小函数内的返回类型?

类型是工作.但它失go 了正确变体的亮点..为什么?或者如何增强?

如何从具有给定键列表的对象类型的联合中构造类型

即使子网是公共的,AWS CDK EventBridge ECS任务也无法分配公共IP地址

忽略和K的定义

在TypeScript中,除了映射类型之外还使用的`in`二进制运算符?

如何为父类构造函数中的修饰属性赋值?

无法正确推断嵌套泛型?

Vue SFC中的多个脚本块共享导入的符号

Angular 15使用react 式表单在数组内部创建动态表单数组

有什么方法可以类型安全地包装import()函数吗?

如何合并两个泛型对象并获得完整的类型安全结果?

在React中定义props 的不同方式.FunctionalComponent

React router 6(数据路由)使用数据重定向

根据类型脚本中的泛型属性 Select 类型

在打印脚本中将对象类型转换为数组

递归JSON类型脚本不接受 node 值中的变量

根据索引将元组拆分为两个块

在 TypeScript 中实现类型级别深度优先搜索

Mongodb TypeError:类继承 events_1.EventEmitter 不是对象或 null