Lesson 54 of 60 – Typing React Components
90%

Typing React Components

In React with TypeScript, components can be given type information for their props, state, functions, children, and other values. This makes reusable components easier to understand and maintain.

Note: React components containing JSX are commonly written in .tsx files when using TypeScript.

1. What is a React Component?

A React component is a reusable piece of UI. It can return JSX that describes what should appear on the screen.

function Welcome() {
    return <h1>Welcome</h1>;
}

2. Function Components

Function components are JavaScript or TypeScript functions that return JSX.

function App() {
    return (
        <div>
            <h1>My App</h1>
        </div>
    );
}

3. TypeScript and Function Components

TypeScript can add types to the data used by a React component.

function Welcome(): JSX.Element {
    return <h1>Welcome</h1>;
}

The component returns JSX.

4. Component Props

Props are values passed from a parent component to a child component.

function Student(props: { name: string }) {
    return <h2>{props.name}</h2>;
}

5. Typing Props with an Interface

An interface can describe the props expected by a component.

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

function Student(props: StudentProps) {
    return (
        <div>
            <h2>{props.name}</h2>
            <p>Age: {props.age}</p>
        </div>
    );
}

6. Destructuring Typed Props

Props can be destructured directly in the function parameter.

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

function Student({
    name,
    age
}: StudentProps) {

    return (
        <div>
            <h2>{name}</h2>
            <p>Age: {age}</p>
        </div>
    );
}

7. Passing Typed Props

<Student
    name="Rahul"
    age={20}
/>

TypeScript checks whether the supplied values match the defined prop types.

8. Required Props

A prop without ? is required.

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

Both name and age must be supplied.

9. Optional Props

Add ? to make a prop optional.

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

Now age can be omitted.

10. Default Value for Optional Props

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

function User({
    name,
    age = 18
}: UserProps) {

    return (
        <p>
            {name} - {age}
        </p>
    );
}

11. String Props

interface MessageProps {
    message: string;
}

function Message({
    message
}: MessageProps) {
    return <p>{message}</p>;
}

12. Number Props

interface ProductProps {
    price: number;
}

function Product({
    price
}: ProductProps) {
    return <p>Price: ₹{price}</p>;
}

13. Boolean Props

interface ButtonProps {
    disabled: boolean;
}

function Button({
    disabled
}: ButtonProps) {

    return (
        <button disabled={disabled}>
            Submit
        </button>
    );
}

14. Array Props

interface ListProps {
    students: string[];
}

function StudentList({
    students
}: ListProps) {

    return (
        <ul>
            {students.map((student) =>
                <li key={student}>
                    {student}
                </li>
            )}
        </ul>
    );
}

15. Object Props

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

interface StudentProps {
    student: Student;
}

function StudentCard({
    student
}: StudentProps) {

    return (
        <div>
            <h2>{student.name}</h2>
            <p>ID: {student.id}</p>
        </div>
    );
}

16. Function Props

A function can also be passed as a prop.

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

function MyButton({
    onClick
}: ButtonProps) {

    return (
        <button onClick={onClick}>
            Click Me
        </button>
    );
}

17. Function Props with Parameters

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

function UserButton({
    onSelect
}: UserProps) {

    return (
        <button onClick={() => onSelect(101)}>
            Select User
        </button>
    );
}

18. Children Props

A component can receive nested content using the children prop.

import { ReactNode } from "react";

interface CardProps {
    children: ReactNode;
}

function Card({
    children
}: CardProps) {

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

19. Using a Children Component

<Card>
    <h2>Student Details</h2>
    <p>Welcome to the course.</p>
</Card>

The nested JSX is received through the children prop.

20. Typing Component Return Values

A React component can explicitly specify an appropriate return type.

function Welcome(): JSX.Element {
    return <h1>Welcome</h1>;
}

In many projects, TypeScript can also infer the component's return type automatically.

21. React.FC Component Type

import React from "react";

const Welcome: React.FC = () => {
    return <h1>Welcome</h1>;
};

React.FC is one way to type a function component. Explicitly typing props is also common.

22. React.FC with Props

interface UserProps {
    name: string;
}

const User: React.FC<UserProps> = ({
    name
}) => {

    return <h2>{name}</h2>;
};

23. Typing useState Inside a Component

import { useState } from "react";

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

function UserProfile() {

    const [user, setUser] =
        useState<User>({
            name: "Rahul",
            age: 20
        });

    return (
        <div>
            <h2>{user.name}</h2>
            <p>{user.age}</p>
        </div>
    );
}

24. Component with Multiple Props

interface ProductProps {
    name: string;
    price: number;
    available: boolean;
}

function Product({
    name,
    price,
    available
}: ProductProps) {

    return (
        <div>
            <h2>{name}</h2>
            <p>Price: ₹{price}</p>
            <p>
                {available
                    ? "Available"
                    : "Not Available"}
            </p>
        </div>
    );
}

25. Reusable Typed Button

interface ButtonProps {
    text: string;
    onClick: () => void;
    disabled?: boolean;
}

function Button({
    text,
    onClick,
    disabled = false
}: ButtonProps) {

    return (
        <button
            onClick={onClick}
            disabled={disabled}
        >
            {text}
        </button>
    );
}

26. Typed Component Event

interface ButtonProps {
    onClick: (
        event: React.MouseEvent<HTMLButtonElement>
    ) => void;
}

function Button({
    onClick
}: ButtonProps) {

    return (
        <button onClick={onClick}>
            Click
        </button>
    );
}

27. Reusable Student Component

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

interface StudentCardProps {
    student: Student;
}

function StudentCard({
    student
}: StudentCardProps) {

    return (
        <div>
            <h2>{student.name}</h2>
            <p>ID: {student.id}</p>
            <p>Course: {student.course}</p>
        </div>
    );
}

28. Parent and Child Typed Components

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

interface StudentListProps {
    students: Student[];
}

function StudentList({
    students
}: StudentListProps) {

    return (
        <div>
            {students.map((student) => (
                <StudentCard
                    key={student.name}
                    student={student}
                />
            ))}
        </div>
    );
}

29. Common Component Typing Mistakes

  • Forgetting to define required props.
  • Passing a string where a number is expected.
  • Using an incorrect function parameter type.
  • Forgetting the optional ? when a prop is optional.
  • Using an incorrect type for children.
  • Using the wrong event type.
  • Duplicating prop definitions instead of creating reusable interfaces.

30. Complete Typed React Component Example

import { useState } from "react";

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

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

function StudentCard({
    student,
    onSelect
}: StudentCardProps) {

    return (
        <div>
            <h2>{student.name}</h2>

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

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

            <button
                onClick={() =>
                    onSelect(student.id)
                }
            >
                Select Student
            </button>
        </div>
    );
}

function App() {

    const [student] = useState<Student>({
        id: 101,
        name: "Rahul",
        course: "React Native"
    });

    const handleSelect = (id: number): void => {
        console.log(
            "Selected Student ID:",
            id
        );
    };

    return (
        <div>
            <h1>Student Details</h1>

            <StudentCard
                student={student}
                onSelect={handleSelect}
            />
        </div>
    );
}

export default App;

This example combines typed objects, typed props, function props, state, and a reusable React component.

📌 Key Points

  • React components can be strongly typed using TypeScript.
  • Props can be typed with interfaces or type aliases.
  • Required props must be supplied by the parent component.
  • Optional props can be created using ?.
  • String, number, boolean, array, and object props can all be typed.
  • Functions passed as props can also be typed.
  • Children can be typed using ReactNode.
  • React state can be given explicit TypeScript types.
  • Typed components improve reusability and maintainability.
  • The same concepts are useful when building React Native components.

🧠 Quick Quiz

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