J. Hesters
J. Hesters

Reputation: 14786

React Native SectionList: What are the correct TypeScript types

I'm building a React Native app using TypeScript. I'm trying to use a SectionList. I followed the docs, and here is my code:

  renderSectionHeader = ({ section: { title } }: { section: { title: string } }) => (
    <ListItem title={title} />
  );

  render() {
    const { sections } = this.props;
    return (
      <SafeAreaView style={styles.container}>
        <SectionList
          keyExtractor={this.keyExtractor}
          sections={[
            {title: 'Title1', data: ['item1', 'item2']},
            {title: 'Title2', data: ['item3', 'item4']},
            {title: 'Title3', data: ['item5', 'item6']},
          ]}
          renderItem={this.renderItem}
          renderSectionHeader={this.renderSectionHeader}
        />
      </SafeAreaView>
    );
  }

But the line renderSectionHeader={this.renderSectionHeader} throws the following TSLint Error:

[ts]
Type '({ section: { title } }: { section: { title: string; }; }) => Element' is not assignable to type '(info: { section: SectionListData<any>; }) => ReactElement<any> | null'.
  Types of parameters '__0' and 'info' are incompatible.
    Type '{ section: SectionListData<any>; }' is not assignable to type '{ section: { title: string; }; }'.
      Types of property 'section' are incompatible.
        Type 'SectionListData<any>' is not assignable to type '{ title: string; }'.
          Property 'title' is missing in type 'SectionListData<any>'. [2322]

Are the types of SectionList broken? Or is the example wrong? Or am I doing something wrong?

Upvotes: 19

Views: 15764

Answers (7)

Ahmed Eid
Ahmed Eid

Reputation: 4804

const sections = [
  {title: 'Title1', data: ['item1', 'item2']},
  {title: 'Title2', data: ['item3', 'item4']},
  {title: 'Title3', data: ['item5', 'item6']},
];

First you need to define the Section type and the Item type:

type Item = string;

type Section = {
  title: string;
  data: Item[];
};

Now you need to define your renderItem function:

const renderItem: SectionListRenderItem<Item, Section> = ({item}) => {
  // return component here
};

Upvotes: 7

James
James

Reputation: 111

import React from 'react';
import {SectionList, SectionListData, SectionListRenderItem, SectionListRenderItemInfo, Text} from 'react-native';

export type Item = string; // <-- Change me

export type Section = {
  title: string;  // <-- Change me
  data: readonly Item[];
}

type ListProps = {
  sections: SectionListData<Item, Section>[],
}

type RenderSectionHeaderArgs = {
  section: SectionListData<Item, Section>
}

const renderSectionItem: SectionListRenderItem<Item> = ({item}) => {
  console.log(item);
  return <Text>{item}</Text>;
};

const renderSectionHeader = ({section: {title, data}}: RenderSectionHeaderArgs) => {
  console.log({title, data});
  return <Text>{title}</Text>;
};

const List: React.FC<ListProps> = ({sections}) => {
  return (
    <SectionList
      sections={sections}
      renderItem={renderSectionItem}
      renderSectionHeader={renderSectionHeader}
    />
  );
};

export default List;

Upvotes: 0

jon
jon

Reputation: 81

This one worked for me:

import type { SectionListData } from 'react-native';

interface Section {
    title?: string;
    data: readonly any[];
}

type SectionHeader = (info: { section: SectionListData<YOUR_ARRAY_TYPE, Section> }) => React.ReactElement;

    const renderSectionHeader: SectionHeader = ({ section: { title } }) => {
        return YOUR_HEADER_COMPONENT;
    };

Upvotes: 4

Yair Levi
Yair Levi

Reputation: 1357

if you know what types you're using and it's only to avoid the warning you could do:

sections={sections as any[]}

Upvotes: -6

mgfjx
mgfjx

Reputation: 71

This is the SectionListData declaration, so you just need to remove the title property, and replace it with key, then TSLint Error will disappear.

export interface SectionBase<ItemT> {
    data: ReadonlyArray<ItemT>;

    key?: string;

    renderItem?: SectionListRenderItem<ItemT>;

    ItemSeparatorComponent?: React.ComponentType<any> | null;

    keyExtractor?: (item: ItemT, index: number) => string;
}

export interface SectionListData<ItemT> extends SectionBase<ItemT> {
    [key: string]: any;
}

enter image description here

Upvotes: 0

user11847380
user11847380

Reputation: 35

interface Data {
...
}

const MySectionList = SectionList as SectionList<Data>;

<MySectionList
...
/>

worked for me

Upvotes: 1

Patryk kowalski
Patryk kowalski

Reputation: 323

I'a new to TypeScript so this question might not be the best but you can check React Native types here: React Native Types github

In line 4243 for now you can see this:

renderSectionHeader?: (info: { section: SectionListData<ItemT> }) => React.ReactElement<any> | null;

This mean that renderSectionHeader property require a function with one argument which is an object with section field of SectionListData<ItemT> type.

To get rid of error that you posted, you can do something like this:

  renderSectionHeader = ({ section: { title } }: { section: { title: string } }): React.ReactElement<any>=> (<ListItem title={title} />)

  render() {
    const { sections } = this.props;
    return (
      <SafeAreaView style={styles.container}>
        <SectionList
          keyExtractor={this.keyExtractor}
          sections={[
            {title: 'Title1', data: ['item1', 'item2']},
            {title: 'Title2', data: ['item3', 'item4']},
            {title: 'Title3', data: ['item5', 'item6']},
          ]}
          renderItem={this.renderItem}
          renderSectionHeader={({section}: {section: SectionListData<string[]>}) => this.renderSectionHeader(section)}
        />
      </SafeAreaView>
    );
  }

Hope this is correct and will help you.

EDIT: If you dont want to provide types during props passing this renderHeader method will be errorless:

renderSectionHeader = ({ section }: {section: SectionListData<string[]>}): ReactElement<any> | null => (<Text>{section.title}</Text>)

Upvotes: 1

Related Questions