Lesson 61 – Typing React Native Components
100%

Typing React Native Components

React Native provides components such as View, Text, TextInput, Button, Pressable, ScrollView, and FlatList. TypeScript helps us use these components correctly by checking their props, values, and event handlers.

Note: React Native components already provide TypeScript definitions. You usually do not need to manually create types for standard component props. Your main task is to correctly type your own component props, state, functions, and data.

1. What Does Typing Components Mean?

Typing components means using TypeScript to describe the data and behavior used by a React Native component.

interface UserProps {
    name: string;
    age: number;
}

function User({
    name,
    age
}: UserProps): React.JSX.Element {

    return (
        <View>
            <Text>{name}</Text>
            <Text>{age}</Text>
        </View>
    );
}

2. Standard React Native Components

Some commonly used React Native components are:

  • View
  • Text
  • TextInput
  • Button
  • Pressable
  • ScrollView
  • FlatList
  • Image
  • ActivityIndicator

3. Typing a View Component

import {
    View,
    Text
} from "react-native";

function Home(): React.JSX.Element {

    return (
        <View>
            <Text>
                Home Screen
            </Text>
        </View>
    );
}

View is commonly used as a container for other React Native components.

4. Typing a Text Component

function Welcome(): React.JSX.Element {

    const name: string = "Rahul";

    return (
        <Text>
            Hello {name}
        </Text>
    );
}

The value displayed inside Text can come from a typed variable.

5. Typing TextInput Values

import {
    TextInput
} from "react-native";

const [name, setName] =
    useState<string>("");

return (
    <TextInput
        value={name}
        onChangeText={setName}
        placeholder="Enter name"
    />
);

The name state is explicitly typed as a string.

6. Typing Button Components

import {
    Button
} from "react-native";

const handlePress = (): void => {
    console.log("Pressed");
};

return (
    <Button
        title="Save"
        onPress={handlePress}
    />
);

7. Typing Pressable

import {
    Pressable,
    Text
} from "react-native";

const handlePress = (): void => {
    console.log("Pressed");
};

return (
    <Pressable
        onPress={handlePress}
    >
        <Text>
            Press Me
        </Text>
    </Pressable>
);

8. Creating Custom Components

TypeScript becomes especially useful when creating your own reusable React Native components.

interface WelcomeProps {
    name: string;
}

function Welcome({
    name
}: WelcomeProps): React.JSX.Element {

    return (
        <Text>
            Welcome {name}
        </Text>
    );
}

9. Passing Props to Custom Components

<Welcome
    name="Rahul"
/>

TypeScript checks that the required name prop is provided.

10. Multiple Component Props

interface StudentCardProps {
    name: string;
    age: number;
    course: string;
}

function StudentCard({
    name,
    age,
    course
}: StudentCardProps): React.JSX.Element {

    return (
        <View>

            <Text>
                Name: {name}
            </Text>

            <Text>
                Age: {age}
            </Text>

            <Text>
                Course: {course}
            </Text>

        </View>
    );
}

11. Optional Component Props

interface UserProps {
    name: string;
    email?: string;
}

function User({
    name,
    email
}: UserProps): React.JSX.Element {

    return (
        <View>

            <Text>
                {name}
            </Text>

            {email && (
                <Text>
                    {email}
                </Text>
            )}

        </View>
    );
}

12. Boolean Props

interface ButtonProps {
    disabled: boolean;
}

function SaveButton({
    disabled
}: ButtonProps): React.JSX.Element {

    return (
        <Button
            title="Save"
            disabled={disabled}
            onPress={() => {}}
        />
    );
}

13. Function Props

interface ButtonProps {
    onPress: () => void;
}

function CustomButton({
    onPress
}: ButtonProps): React.JSX.Element {

    return (
        <Button
            title="Click"
            onPress={onPress}
        />
    );
}

A function prop allows a parent component to control an action performed by the child.

14. Function Props with Parameters

interface StudentProps {
    id: number;
    onSelect: (id: number) => void;
}

function StudentButton({
    id,
    onSelect
}: StudentProps): React.JSX.Element {

    return (
        <Button
            title="Select"
            onPress={() =>
                onSelect(id)
            }
        />
    );
}

15. Typing Children

import {
    ReactNode
} from "react";

interface CardProps {
    children: ReactNode;
}

function Card({
    children
}: CardProps): React.JSX.Element {

    return (
        <View>
            {children}
        </View>
    );
}

ReactNode can be used when a component accepts React content through children.

16. Image Component

import {
    Image
} from "react-native";

function ProfileImage(): React.JSX.Element {

    return (
        <Image
            source={{
                uri: "https://example.com/user.jpg"
            }}
            style={{
                width: 100,
                height: 100
            }}
        />
    );
}

The Image component is used to display images in React Native applications.

17. ScrollView Component

import {
    ScrollView,
    Text
} from "react-native";

function About(): React.JSX.Element {

    return (
        <ScrollView>

            <Text>
                React Native content
            </Text>

            <Text>
                More content
            </Text>

        </ScrollView>
    );
}

18. FlatList Component

interface Student {
    id: number;
    name: string;
}

interface Props {
    students: Student[];
}

function StudentList({
    students
}: Props): React.JSX.Element {

    return (
        <FlatList
            data={students}
            keyExtractor={(item) =>
                item.id.toString()
            }
            renderItem={({ item }) => (
                <Text>
                    {item.name}
                </Text>
            )}
        />
    );
}

19. SectionList Component

interface Student {
    id: string;
    name: string;
}

interface StudentSection {
    title: string;
    data: Student[];
}

TypeScript can describe the structure of section data before passing it to a SectionList.

20. ActivityIndicator

import {
    ActivityIndicator
} from "react-native";

const [loading, setLoading] =
    useState<boolean>(true);

return (
    <View>

        {loading && (
            <ActivityIndicator
                size="large"
            />
        )}

    </View>
);

21. Typing Component State

interface User {
    id: number;
    name: string;
}

const [user, setUser] =
    useState<User | null>(null);

The state can contain either a User object or null.

22. Typed Component with API Data

interface Product {
    id: number;
    name: string;
    price: number;
}

function ProductCard({
    product
}: {
    product: Product;
}): React.JSX.Element {

    return (
        <View>

            <Text>
                {product.name}
            </Text>

            <Text>
                ₹{product.price}
            </Text>

        </View>
    );
}

23. Typing TextInput Handlers

const handleNameChange = (
    text: string
): void => {

    setName(text);
};

return (
    <TextInput
        value={name}
        onChangeText={handleNameChange}
    />
);

React Native's onChangeText callback provides the new text directly as a string.

24. Typing Pressable Events

const handlePress = (): void => {

    console.log(
        "Pressable clicked"
    );
};

return (
    <Pressable
        onPress={handlePress}
    >

        <Text>
            Open
        </Text>

    </Pressable>
);

25. Typing Component Styles

import {
    StyleSheet,
    View
} from "react-native";

function Screen(): React.JSX.Element {

    return (
        <View
            style={styles.container}
        />
    );
}

const styles = StyleSheet.create({

    container: {
        flex: 1,
        padding: 20
    }

});

StyleSheet.create() provides type checking for React Native style properties.

26. Common Component Typing Mistakes

  • Passing a string where a number prop is expected.
  • Forgetting required props.
  • Using incorrect function parameter types.
  • Using browser DOM event types for React Native events.
  • Using an incorrect interface for API data.
  • Forgetting that nullable state needs a union type.
  • Using incorrect data types in FlatList items.

27. Reusable Typed Button

interface AppButtonProps {
    title: string;
    onPress: () => void;
    disabled?: boolean;
}

function AppButton({
    title,
    onPress,
    disabled = false
}: AppButtonProps): React.JSX.Element {

    return (
        <Button
            title={title}
            onPress={onPress}
            disabled={disabled}
        />
    );
}

28. Reusable Typed Input

interface AppInputProps {
    value: string;
    placeholder?: string;
    onChangeText: (
        text: string
    ) => void;
}

function AppInput({
    value,
    placeholder,
    onChangeText
}: AppInputProps): React.JSX.Element {

    return (
        <TextInput
            value={value}
            placeholder={placeholder}
            onChangeText={onChangeText}
        />
    );
}

29. Best Practices for Typed Components

  • Create interfaces for complex component props.
  • Use meaningful names for prop interfaces.
  • Use explicit types for complex state.
  • Type callback functions correctly.
  • Use the correct React Native event signatures.
  • Type API and FlatList data structures.
  • Create reusable typed components for common UI elements.
  • Keep component responsibilities small.

30. Complete Typed React Native Component Example

import {
    useState
} from "react";

import {
    View,
    Text,
    TextInput,
    Button,
    StyleSheet
} from "react-native";

interface Student {
    id: number;
    name: string;
    course: string;
}

interface StudentCardProps {
    student: Student;
    onDelete: (
        id: number
    ) => void;
}

function StudentCard({
    student,
    onDelete
}: StudentCardProps): React.JSX.Element {

    return (
        <View style={styles.card}>

            <Text style={styles.name}>
                {student.name}
            </Text>

            <Text>
                ID: {student.id}
            </Text>

            <Text>
                Course: {student.course}
            </Text>

            <Button
                title="Delete"
                onPress={() =>
                    onDelete(student.id)
                }
            />

        </View>
    );
}

function App(): React.JSX.Element {

    const [name, setName] =
        useState<string>("");

    const [students, setStudents] =
        useState<Student[]>([]);

    const addStudent = (): void => {

        if (!name.trim()) {
            return;
        }

        const student: Student = {
            id: Date.now(),
            name: name,
            course: "React Native"
        };

        setStudents(
            previousStudents => [
                ...previousStudents,
                student
            ]
        );

        setName("");
    };

    const deleteStudent = (
        id: number
    ): void => {

        setStudents(
            previousStudents =>
                previousStudents.filter(
                    student =>
                        student.id !== id
                )
        );
    };

    return (
        <View style={styles.container}>

            <Text style={styles.title}>
                Student Management
            </Text>

            <TextInput
                style={styles.input}
                value={name}
                onChangeText={setName}
                placeholder="Enter student name"
            />

            <Button
                title="Add Student"
                onPress={addStudent}
            />

            {students.map(student => (

                <StudentCard
                    key={student.id}
                    student={student}
                    onDelete={deleteStudent}
                />

            ))}

        </View>
    );
}

const styles = StyleSheet.create({

    container: {
        flex: 1,
        padding: 20,
        paddingTop: 60
    },

    title: {
        fontSize: 24,
        fontWeight: "bold",
        marginBottom: 20
    },

    input: {
        borderWidth: 1,
        padding: 10,
        marginBottom: 15
    },

    card: {
        borderWidth: 1,
        padding: 15,
        marginTop: 10
    },

    name: {
        fontSize: 18,
        fontWeight: "bold"
    }

});

export default App;

This example combines interfaces, typed props, typed state, TextInput, Button, callback functions, arrays, reusable components, and React Native styles.

📌 Key Points

  • React Native provides built-in TypeScript definitions for its components.
  • Custom component props should be typed with interfaces or type aliases.
  • Use typed state for strings, numbers, booleans, arrays, and objects.
  • Type callback functions such as onPress and onChangeText.
  • Use ReactNode when a custom component accepts children.
  • Type FlatList and API data with interfaces.
  • Use nullable union types when state can contain null.
  • Reusable typed components make React Native applications easier to maintain.
  • TypeScript is especially useful for larger React Native projects.

🧠 Quick Quiz

Question: Which TypeScript feature is commonly used to define the props of a custom React Native component?