TypeScript React Native Flatlist:如何为renderItem提供正确的项目类型?

J. *_*ers 1 object typescript react-native typescript-typings react-native-flatlist

我正在用TypeScript构建一个React Native应用程序。renderItem抱怨解构后的项目隐式具有any类型。我用Google搜索,发现了这个问题,并试图实现他们在这里任教,在类型组合index.d.ts中的@types包本机作出反应。

export interface Props {
  emotions: Emotion[];
}

class EmotionsPicker extends PureComponent<Props> {
  keyExtractor = (item, index) => index;
  renderItem = ({ item }) => (
    <ListItem title={item.name} checkmark={item.checked} />
  );

  render() {
    return (
      <FlatList<Emotion>
        keyExtractor={this.keyExtractor}
        renderItem={this.renderItem}
        data={this.props.emotions}
      />
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

不幸的是,这不起作用。我该如何指定商品类型Emotion

小智 39

我知道这是一个老问题,但谷歌搜索它的人可能仍然会欣赏它。

import { FlatList, ListRenderItem } from 'react-native'
/*
.
.
.
*/
  renderItem: ListRenderItem<Emoticon> = ({ item }) => (
    <ListItem title={item.name} checkmark={item.checked} />
  );
Run Code Online (Sandbox Code Playgroud)


小智 19

我找到了一个对我来说非常有效的解决方案:

import { FlatList, ListRenderItemInfo } from 'react-native';


<FlatList
  data={data}
  renderItem={({ item }: ListRenderItemInfo<ItemType>) => (
    <ItemComponent item={item} />
  )}
  keyExtractor={(item: ItemType) => item.id}
/>
Run Code Online (Sandbox Code Playgroud)


J. *_*ers 11

我找到了一个解决方案(尽管我不知道它是否理想):

renderItem = ({ item }: { item: Emotion }) => (
  <ListItem title={item.name} checkmark={item.chosen} />
);
Run Code Online (Sandbox Code Playgroud)


小智 7

如果不是内联函数,解构时从 React 导出的正确类型是ListRenderItemInfo<ItemT>

export interface ListRenderItemInfo<ItemT> {
    item: ItemT;

    index: number;

    separators: {
        highlight: () => void;
        unhighlight: () => void;
        updateProps: (select: "leading" | "trailing", newProps: any) => void;
    };
}
Run Code Online (Sandbox Code Playgroud)


Mad*_*iha 5

这是因为在renderItem定义时间时,TypeScript无法知道它应该作为的renderItem支持FlatList

如果您已跳过变量并直接将属性放入prop中,则TypeScript应该能够正确推断出它:

export interface Props {
  emotions: Emotion[];
}

class EmotionsPicker extends PureComponent<Props> {    
  render() {
    return (
      <FlatList<Emotion>
        keyExtractor={(item, index) => index}
        renderItem={({ item }) => <ListItem title={item.name} checkmark={item.checked} />}
        data={this.props.emotions}
      />
    );
  }
}
Run Code Online (Sandbox Code Playgroud)


Raw*_*lus 5

我觉得这里的答案只解决了如何在更好的情况下修复,在更坏的情况下绕过类型检查,但无法解释为什么它不起作用或者为什么应该按原样输入。

我想更清楚地解释为什么这对大多数人来说会失败,因为即使在官方的 Wiki 上,它的记录也非常少。


为什么你会收到错误:

组件FlatList方法不需要通常用于传递(即)标准 React 元素构造函数的渲染函数(props) => JSX.Element

无论好坏,FlatListrenderItem方法的键入方式如下:

type ListRenderItem<ItemT> = (info: ListRenderItemInfo<ItemT>) =>
   React.ReactElement | null;
Run Code Online (Sandbox Code Playgroud)

这是因为它不需要直接元素构造函数,就像您renderItem在大多数 React 模式中习惯的那样标准构造方法。

相反,它需要一个特定类型的回调。这是为了优化目的的内部处理,但在输入时仍然相当笨重。

export interface ListRenderItemInfo<ItemT> {
    item: ItemT;
    index: number;
    separators: {
        highlight: () => void;
        unhighlight: () => void;
        updateProps: (select: 'leading' | 'trailing', newProps: any) => void;
    };
}
Run Code Online (Sandbox Code Playgroud)

输入函数的正确方法

因此,这意味着我们应该将我们自己的内部renderItem视为回调,以及传递特定<ItemT>泛型的特定项目道具

type Props = {
  emotions: Emotion[]
}

// This is the standard React function component
const Item = (({ title, checked }): Emotion) => (
   <ListItem title={title} checked={checked} />
)

// This is the callback for constructing the function component
const renderItem: ListRenderItem<Emotion> = ({ item }: ListRenderItemInfo<Emotion>) => (
   <Item title={item.title} checked={item.checked} />
)
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,乍一看这可能相当令人困惑并且很容易混淆。在ListRenderItem<T>Tell 打字稿中,我们希望创建一个类型T(通用参数)的函数,然后构造(返回)一个Reat.ReactElement | null. 但由于 React 组件本身就是函数,我们仍然需要传递函数来创建一个。这就是混乱和类型错误的根源。

这本质上是

  1. 创建一个回调ListRenderItem<T>
  2. 只接受ListRenderItemInfo<T>prop的特定 propTypeitem
  3. 然后需要构造函数(props: T) => JSX.Element

而不是传递道具并从中创建元素的标准方式。这也是您收到以下错误的原因:

Property 'property name' does not exist on ListRenderItem<any>
Run Code Online (Sandbox Code Playgroud)