使用 TypeScript 响应 FlatList

IT技术 reactjs typescript
2021-05-20 05:58:18

TypeScript 真的很棒,就目前而言,我觉得我为 TypeScript 工作比 TypeScript 更适合我。

我有一个 FlatList,它在旋转木马中呈现餐厅结果。

 const renderRestaurantRows = ({ item }) => (
    <Carousel
      id={item.id}
      name={item.name}
    />
  );
  const renderBottomSheetRestaurantList = () => (
    <View style={[styles.listView, { height: topSnapPoint }]}>
      <FlatList
        data={restaurants}
        keyExtractor={(item) => `row-${item.id}`}
        renderItem={renderRestaurantRows}
      />
    </View>
  );

TypeScript 抱怨itemwith Binding element 'item' implicitly has an 'any' type- 是有道理的。所以我试着告诉它会发生什么:

  interface RestaurantItem {
    item: {
      id: string;
      name: string;
    };
  }
  const renderRestaurantRows = ({ item }: RestaurantItem) => (
    <Carousel
      id={item.id}
      name={item.name}
    />
  );

但随后TS抱怨data={restaurants]Type 'Restaurant[]' is not assignable to type 'readonly { id: string; name: string; imageUrl: string; rating: number; reviews: number; }和一吨的其他信息。

有人可以分享解决方案并解释将来如何为其他类似案例找到这样的解决方案吗?

更新

restaurants从自定义钩子中获取。它被定义为一个 Restaurant 对象数组:

interface Restaurant {
  id: string;
  name: string;
}
export default function useRestaurantSearch() {
  const [restaurants, setRestaurants] = useState<Restaurant[] | null>(null);
  ...

更新 2

伙计们感谢您的评论,按照两个建议,我重写了代码:

import useRestaurantSearch from '../hooks/useRestaurantSearch';
export default function RestaurantPage() {
  const renderRestaurantRows = ({ item }: Restaurant) => (
    <Carousel
      id={item.id}
      name={item.name}
    />
  );
  const renderBottomSheetRestaurantList = () => (
    <View style={[styles.listView, { height: topSnapPoint }]}>
      <FlatList
        data={restaurants}
        keyExtractor={(item) => `row-${item.id}`}
        renderItem={renderRestaurantRows}
      />
    </View>
  );

这次我收到了一个错误{ item }: Restaurantwith Cannot find name 'Restaurant'这并不奇怪,因为 Restaurant 是在外部 hooks 文件中定义的../hooks/useRestaurantSearch我需要以某种方式导入它吗?

更新 3

在玩了几个小时之后,我到了这一点:

  const renderRestaurantRows = (result: { item: Restaurant }) => {
    return <Carousel {...result.item} />;
  };
  const renderBottomSheetRestaurantList = () => (
    <View style={[styles.listView, { height: topSnapPoint }]}>
      <FlatList
        data={restaurants}
        keyExtractor={(item) => `row-${item.id}`}
        renderItem={renderRestaurantRows}
      />
    </View>
  );

renderItem生成一个对象,其中包含一个item下的每个餐厅数据例如,对象之一可能是:

{
  "index": 18,
  "item": Object {
    "coordinates": Object {
      "latitude": 123,
      "longitude": -123,
    },
    "id": "dfg987fshjsdfh",
    "name": "Yummy Food",
  },
  "separators": Object {
    "highlight": [Function highlight],
    "unhighlight": [Function unhighlight],
    "updateProps": [Function updateProps],
  },
}

当我传递一个result对象时,我可以让 TS 知道item该对象的内部并将其转换为 Restaurant 类型。我用 (result: { item: Restaurant }) . However, when I try to directly destructure the result object with({ item }: Restaurant)it gives me the error属性 'item' 在类型 'Restaurant'` 上不存在。知道为什么吗?

2个回答

尝试导入 ListRenderItem 并输入接收函数的常量:

import { ListRenderItem } from 'react-native';
...
const renderRestaurantRows: ListRenderItem<Restaurant> = ({ item }) => (
  <Carousel
    id={item.id}
    name={item.name}
  />
);

你真正从 renderItems 得到的参数是:

列表渲染项

ItemT你的类型在哪里Restaurant

假设要呈现的项目是一个Movie

    _renderItem(info: ListRenderItemInfo<Movie>): ReactElement<Movie> {
        return <MovieTile movie={info.item} />;
    }

    render() {
        let movies = this.props.movies;

        return <FlatList
            data={movies}
            horizontal={true}
            renderItem={this._renderItem}
            keyExtractor={(item, i) => item.id.toString()}
            />;
    }