hyochan / react-native-masonry-list

The Masonry List implementation which has similar implementation as the `FlatList` in React Native
MIT License
399 stars 55 forks source link

TypeScript: Type 'unknown' is not assignable to type 'IntrinsicAttributes' #69

Open sofi-algoritcom opened 6 months ago

sofi-algoritcom commented 6 months ago

Describe the bug When using the MasonryList component in a TypaScript project, the renderItem prop param item is not being typed as the elements given to the data prop array, but it is type 'unknown' so when rendering the item, ts raises this problem.

If I use FlatList or ScrollView instead, I don't get this warning.

To Reproduce Steps to reproduce the behavior:

  1. Create TypeScript project.
  2. Define this constants:
    
    interface PostPreviewProps {
    id: string;
    imgUrl: string;
    }

const posts: PostPreviewProps[] = [ { id: '1', imgUrl: 'https://img.freepik.com/free-photo/delicious-donuts_144627-6267.jpg?t=st=1708687137~exp=1708690737~hmac=f9cf5f46c098a440e9581533fe07c587d300dfc22b44d0cc7cdb1b6810503314&w=1480', }, { id: '2', imgUrl: 'https://img.freepik.com/free-photo/vertical-shot-fox-walking-rocks-forest_181624-31966.jpg?t=st=1708686685~exp=1708690285~hmac=b7d67c6f8bf2576069aaa00308da904b12ae956275498340427b94165f880a60&w=996', }, ];

3. Define the following component to render the item:

function PostPreview(props: PostPreviewProps): JSX.Element { return (

); }

5. Render the following:

<MasonryList data={posts} renderItem={({ item }) => ( <PostPreview {...item} /> )} />


6. See ts problem

**Expected behavior**
The `item` param from the `renderItem` callback should have type `PostPreviewProps`, since the data value (posts) is an array of such item type. Both `FlatList` and `ScrollView` do this automatically, but this `MasonryList` component says `item` is type `unknown`, which causes the `ts` problem reported when passed item as props to the `PostPreview` component.

**Screenshots**
<img width="344" alt="Captura de pantalla 2024-04-03 a las 16 03 52" src="https://github.com/hyochan/react-native-masonry-list/assets/160500407/6484f8db-fe74-419a-89a9-604f0e45ee8a">
<img width="523" alt="Captura de pantalla 2024-04-03 a las 16 08 09" src="https://github.com/hyochan/react-native-masonry-list/assets/160500407/01f4aab5-7674-4800-b7db-762e6a349d7e">
Fexxix commented 2 months ago

This might just be a problem with react's types itself. Let me explain:

  // the signature for the MasonryList is this
  declare const MasonryList = <T>(props: Props<T>) => ReactElement;
  // this should work fine but this isn't the type which the library consumer ends up using
  // because the component is memoized so the .d.ts file instead exports this

  declare const _default: React.MemoExoticComponent<typeof MasonryList>;
  // this, for some reason, breaks sound typing in generic components

Paste this code into your IDE to see what i mean

import React, { memo } from "react"
import { FlatList } from "react-native"

type ListProps<T> = {
  data: T[];
};

const List = <T,>({ data }: ListProps<T>) => {
  return (
    <FlatList
      data={data}
      renderItem={() => null}
      keyExtractor={() => ""}
    />
  );
};

<List
// hover over data to see that it is correctly typed
data={[1,2]}
/>

const MemoList = memo(List)

;() => <MemoList
  // hover over data to see that it is not correctly typed and is instead typed as unknown[]
  data={[1, 3]}
/>

// also the type of this below and the `MemoList` are not the same
type MemoListType = React.MemoExoticComponent<typeof List>