Reputation: 1924
SO community,
I can't figure out the correct type definition for an RN FlatList styled with Styled Components in Typescript
So I have type IProduct
like that
interface IProduct {
id: string;
name: string;
}
and I define the types for the FlatList
like that
<FlatList
data={products}
renderItem={({ item }: { item: IProduct }) => (
<SomeComponent item={item} />
)}
keyExtractor={(item: IProduct) => item.id}
/>
everything works fine. Typescript does not complain but as soon as I want to style the FlatList
like that
const StyledFlatList = styled.FlatList`
background-color: 'white';
`;
<StyledFlatList
data={products}
renderItem={({ item }: { item: IProduct }) => (
<SomeComponent item={item} />
)}
keyExtractor={(item: IProduct) => item.id}
/>
I get lots of Typescript errors
No overload matches this call.
Overload 2 of 2, '(props: StyledComponentPropsWithAs<typeof FlatList, DefaultTheme, {}, never>): ReactElement<StyledComponentPropsWithAs<typeof FlatList, DefaultTheme, {}, never>, string | ... 1 more ... | (new (props: any) => Component<...>)>', gave the following error.
Type '({ item }: { item: IProduct; }) => JSX.Element' is not assignable to type 'ListRenderItem<unknown>'.
Overload 2 of 2, '(props: StyledComponentPropsWithAs<typeof FlatList, DefaultTheme, {}, never>):
ReactElement<StyledComponentPropsWithAs<typeof FlatList, DefaultTheme, {}, never>, string | ... 1 more ... | (new (props: any) => Component<...>)>', gave the following error.
Type '(item: IProduct) => string' is not assignable to type '(item: unknown, index: number) => string'.ts(2769)
index.d.ts(4218, 5): The expected type comes from property 'keyExtractor' which is declared here on type 'IntrinsicAttributes & Pick<Pick<FlatListProps<unknown> & RefAttributes<FlatList<unknown>>, "ref" | "data" | "style" | "ItemSeparatorComponent" | ... 141 more ... | "key"> & Partial<...>, "ref" | ... 144 more ... | "key"> & { ...; } & { ...; } & { ...; }'
index.d.ts(4218, 5): The expected type comes from property 'keyExtractor' which is declared here on type 'IntrinsicAttributes & Pick<Pick<FlatListProps<unknown> & RefAttributes<FlatList<unknown>>, "ref" | "data" | "style" | "ItemSeparatorComponent" | ... 141 more ... | "key"> & Partial<...>, "ref" | ... 144 more ... | "key"> & { ...; } & { ...; } & { ...; }'
Can someone tell me how to fix that error?
Upvotes: 11
Views: 10625
Reputation: 5059
You can define a custom styled-components FlatList
type that accepts IProduct
as follows:
import styled from 'styled-components';
import { FlatList, FlatListProps } from 'react-native';
import IProduct from './Product.d';
export const StyledFlatList = styled(FlatList as new (props: FlatListProps<IProduct>) => FlatList<IProduct>)`
// your styles
`;
Then use it in your .tsx
<StyledFlatList
data={products}
renderItem={({ item }) => <SomeComponent item={item} />}
keyExtractor={(item: IProduct) => item.id}
/>
Upvotes: 0
Reputation: 74
This is how it worked for me, after some tests (and mergin the sugestions on this topic):
At styles.ts, my typed FlatList ended like this:
export const CustomFlatList = styled(FlatList as typeof FlatList<EstablishmentTransactionAntecipationDTO>)`
flex: 1;
width: 100%;
`;
Upvotes: 1
Reputation: 31
I think you just need to inform the generic type with, styled.FlatList``
import styled from 'styled-components/native';
const StyledFlatList = styled.FlatList<IProduct>`
background-color: #f7f7f7;
`;
Upvotes: 3
Reputation: 385
Looks like adding typeof
to another suggested solution solved this in a more straightforward way, even allowing you to exclude types from props:
const StyledFlatList = (styled.FlatList`
background-color: 'white';
` as unknown) as typeof FlatList;
<StyledFlatList
data={products}
renderItem={({ item }) => (
<SomeComponent item={item} />
)}
keyExtractor={(item) => item.id}
/>
Upvotes: 18
Reputation: 1141
This simple solution works for me:
interface IProduct {
id: string;
name: string;
}
const StyledFlatList = styled(FlatList as new () => FlatList<IProduct>)`
background-color: #f7f7f7;
`
Upvotes: 6
Reputation: 1924
After a few trial and error runs I think I found a solution that works but it's not ideal.
<StyledFlatList<any>
data={products}
renderItem={({ item }: { item: IProduct }) => (
<ProductCard product={item} onProductPress={handleOnProductPress} />
)}
keyExtractor={(item: IProduct) => item.id}
/>
Let me know if that looks OK with you.
UPDATE 1:
If I add the code snippet Ben Clayton suggested, prettier will format the code like that
const StyledFlatList = (styled.FlatList`
background-color: ${colors.silver};
` as unknown) as FlatList;
and I get a TS error
JSX element type 'StyledFlatList' does not have any construct or call signatures.
UPDATE 2:
Instead of <any>
I tried <React.ElementType>
as suggested here which seems to work too.
<StyledFlatList<React.ElementType>
data={products}
renderItem={({ item }: { item: IProduct }) => (
<ProductCard product={item} onProductPress={handleOnProductPress} />
)}
keyExtractor={(item: IProduct) => item.id}
/>
Upvotes: 0