FlatList is one of the most commonly used React Native
components for displaying lists of data. When working with TypeScript,
we can define the type of each item in the list and make our FlatList
code safer and easier to understand.
FlatList<T>.
FlatList is a React Native component used to efficiently
display a list of items.
import { FlatList } from "react-native";
It is useful when an application needs to display many records such as students, products, users, messages, or posts.
Without proper types, it can be difficult to know which properties are available on each list item.
TypeScript allows us to define the exact structure of every item.
interface Student {
id: number;
name: string;
course: string;
}
const students: Student[] = [
{
id: 1,
name: "Rahul",
course: "React Native"
},
{
id: 2,
name: "Priya",
course: "TypeScript"
}
];
The Student[] type means every item must follow the
Student interface.
<FlatList<Student>
data={students}
renderItem={({ item }) => (
<Text>{item.name}</Text>
)}
/>
FlatList<Student> tells TypeScript that every item
in the list is a Student.
The syntax below uses a generic type:
FlatList<Student>
Here, Student represents the type of one item in the list.
This allows TypeScript to understand the structure of
item inside renderItem.
The renderItem callback receives information about the
current item.
renderItem={({ item }) => (
<Text>{item.name}</Text>
)}
Because FlatList is typed as Student, TypeScript knows that
item is a Student.
<Text>
{item.name}
</Text>
<Text>
{item.course}
</Text>
TypeScript provides information about the properties available on
item.
keyExtractor provides a unique key for each list item.
keyExtractor={(item) =>
item.id.toString()
}
If id is a number, converting it to a string is a common
approach for the key.
keyExtractor={(item: Student) =>
item.id.toString()
}
The explicit type is usually not necessary when FlatList is already correctly typed, but it can make the expected item type clearer.
import {
FlatList,
Text
} from "react-native";
interface Student {
id: number;
name: string;
}
const students: Student[] = [
{
id: 1,
name: "Rahul"
},
{
id: 2,
name: "Priya"
}
];
<FlatList<Student>
data={students}
keyExtractor={(item) =>
item.id.toString()
}
renderItem={({ item }) => (
<Text>{item.name}</Text>
)}
/>
A list item can contain several properties.
interface Product {
id: number;
name: string;
price: number;
}
const products: Product[] = [
{
id: 1,
name: "Keyboard",
price: 800
},
{
id: 2,
name: "Mouse",
price: 500
}
];
<FlatList<Product>
data={products}
renderItem={({ item }) => (
<View>
<Text>
{item.name}
</Text>
<Text>
₹{item.price}
</Text>
</View>
)}
/>
TypeScript knows that item.name is a string and
item.price is a number.
const [students, setStudents] =
useState<Student[]>([]);
This is useful when list data changes during application execution.
<FlatList<Student>
data={students}
renderItem={({ item }) => (
<Text>{item.name}</Text>
)}
/>
setStudents(prev => [
...prev,
{
id: 3,
name: "Amit",
course: "JavaScript"
}
]);
TypeScript checks that the new object follows the Student structure.
setStudents(prev =>
prev.filter(student =>
student.id !== 2
)
);
The filtered result remains a Student[].
FlatList is commonly used to display data received from an API.
const [students, setStudents] =
useState<Student[]>([]);
const response =
await fetch(url);
const data: Student[] =
await response.json();
setStudents(data);
if (loading) {
return (
<ActivityIndicator />
);
}
return (
<FlatList<Student>
data={students}
renderItem={({ item }) => (
<Text>{item.name}</Text>
)}
/>
);
A loading indicator can be displayed while data is being requested.
ListEmptyComponent can display a message when the list
contains no data.
<FlatList<Student>
data={students}
renderItem={({ item }) => (
<Text>{item.name}</Text>
)}
ListEmptyComponent={
<Text>No students found.</Text>
}
/>
renderItem={({ item }) => (
<Pressable
onPress={() =>
console.log(item.id)
}
>
<Text>
{item.name}
</Text>
</Pressable>
)}
The typed item can be used safely inside the press handler.
interface StudentItemProps {
student: Student;
}
function StudentItem(
{ student }: StudentItemProps
): React.JSX.Element {
return (
<View>
<Text>
{student.name}
</Text>
</View>
);
}
A separate component can make large FlatList implementations easier to maintain.
<FlatList<Student>
data={students}
keyExtractor={(item) =>
item.id.toString()
}
renderItem={({ item }) => (
<StudentItem
student={item}
/>
)}
/>
interface Student {
id: number;
name: string;
course?: string;
}
If course is optional, handle it safely when displaying it.
<Text>
{item.course ?? "Course not available"}
</Text>
any for all list data.FlatList<YourType>.keyExtractor.any.A reusable list item can receive a typed function to handle selection.
interface StudentItemProps {
student: Student;
onSelect: (student: Student) => void;
}
This ensures that the function receives a Student object.
const handleStudent =
(student: Student): void => {
console.log(student.id);
console.log(student.name);
};
The function can then be passed to a reusable list item.
A typed FlatList can also be used with a refresh state.
const [refreshing, setRefreshing] =
useState<boolean>(false);
<FlatList<Student>
data={students}
refreshing={refreshing}
onRefresh={loadStudents}
renderItem={({ item }) => (
<Text>{item.name}</Text>
)}
/>
import React, {
useState
} from "react";
import {
View,
Text,
FlatList,
Pressable,
StyleSheet
} from "react-native";
interface Student {
id: number;
name: string;
course: string;
}
const students: Student[] = [
{
id: 1,
name: "Rahul",
course: "React Native"
},
{
id: 2,
name: "Priya",
course: "TypeScript"
},
{
id: 3,
name: "Amit",
course: "JavaScript"
}
];
export default function App(): React.JSX.Element {
const [selectedId, setSelectedId] =
useState<number | null>(null);
const handleSelect =
(student: Student): void => {
setSelectedId(student.id);
};
return (
<View style={styles.container}>
<Text style={styles.title}>
Student List
</Text>
<FlatList<Student>
data={students}
keyExtractor={(item) =>
item.id.toString()
}
renderItem={({ item }) => (
<Pressable
style={styles.item}
onPress={() =>
handleSelect(item)
}
>
<Text style={styles.name}>
{item.name}
</Text>
<Text>
{item.course}
</Text>
{selectedId === item.id && (
<Text>
Selected
</Text>
)}
</Pressable>
)}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20
},
title: {
fontSize: 24,
fontWeight: "bold",
marginBottom: 15
},
item: {
padding: 15,
marginBottom: 10,
borderWidth: 1,
borderRadius: 8
},
name: {
fontSize: 18,
fontWeight: "bold"
}
});
TypeScript makes FlatList code easier to understand and maintain. When the list is typed, the editor can provide suggestions and detect many incorrect property accesses during development.
FlatList is an important React Native component for displaying lists. TypeScript allows us to define the structure of each list item and pass that type to FlatList.
You should now understand interfaces for list data, typed FlatList, renderItem, keyExtractor, API data, useState, reusable list items, optional properties, selection, refreshing, and common TypeScript practices for FlatList.
FlatList<Student> to type list items.useState<Student[]>.keyExtractor.any when a proper type can be defined.Question: Which syntax correctly tells TypeScript that a FlatList contains Student objects?