TypeScript + React Hands-on

TypeScript provides complete type support for React development, improving code reliability.

Using TypeScript ensures that React components, Props, State, etc., all have complete type checking, reducing runtime errors.

View the React tutorial:https://www.example.com/vue3/react-tutorial.html


SVG Diagram: React + TypeScript Development Workflow Background Title React + TypeScript Type Support Components React Components React.FC<Props> interface ButtonProps { text: string React Hooks useState<T>(initial) useEffect(() => {}, []) useCallback<T>(fn) Events Event Handling React.FormEvent React.ChangeEvent React.MouseEvent Bottom half: Type Safety Advantages Brought by TypeScript Advantage 1 Compile-time Type Checking Advantage 2 Intelligent Code Completion Advantage 3 Safer Refactoring Arrow marker

Why do you need to use TypeScript in React?

React component-based development produces a large amount of data flow such as Props, State, Context, etc.

Without type definitions, it is difficult to track the source and structure of data, and runtime errors are likely to occur.

TypeScript provides a complete type system for React: component Props have type checking, useState has type inference, and event handling has type hints.

Data flow:The data flow in React (Props, State, Context) needs type definitions, and TypeScript can ensure the type safety of the data flow.


Create a Project

Use a modern scaffolding tool to create a React project that supports TypeScript.

Initialize

# Use Create React App (slower but complete)
npx create-react-app my-app --template typescript

# Or use Vite (recommended, faster)
npm create vite@latest my-app -- --template react-ts

Recommendation:Vite is currently the most recommended React build tool, with fast speed and a good development experience.


Component Types

Use the React.FC type to define function components.

src/components/Button.tsx

import React from "react";

// Define the Props type for the button component
interface ButtonProps {
    text: string;                    // Button text (required)
    onClick: () => void;             // Click callback (required)
    disabled?: boolean;              // Whether disabled (optional, default false)
    variant?: "primary" | "secondary"; // Button variant (optional)
}

// Define the function component type using React.FC
const Button: React.FC<ButtonProps> = ({
    text,
    onClick,
    disabled = false,
    variant = "primary"
}) => {
    return (
        <button
            className={`btn btn-${variant}`}
            onClick={onClick}
            disabled={disabled}
        >
            {text}
        </button>
    );
};

export default Button;

Running result:

Button 组件渲染成功

React.FC:This is the type of a React function component, including built-in types such as children, propTypes, etc.


Props Types

Define the Props interface of a component to pass data to child components.

src/components/UserCard.tsx

import React from "react";

// Define the user type
interface User {
    id: number;           // User ID
    name: string;        // Username
    email: string;       // Email
    avatar?: string;     // Avatar (optional)
}

// Define the Props for the user card component
interface UserCardProps {
    user: User;                       // User object (required)
    onEdit: (user: User) => void;    // Edit callback
    onDelete: (id: number) => void;  // Delete callback
}

const UserCard: React.FC<UserCardProps> = ({ user, onEdit, onDelete }) => {
    return (
        <div className="user-card">
            {user.avatar && <img src={user.avatar} alt={user.name} />}
            <h3>{user.name}</h3>
            <p>{user.email}</p>
            <button onClick={() => onEdit(user)}>Edit</button>
            <button onClick={() => onDelete(user.id)}>Delete</button>
        </div>
    );
};

export default UserCard;
Type propagation:Pass types through Props to ensure consistent data types across the component tree.

useState Types

Provide type parameters for useState to ensure the correct state type.

src/components/Counter.tsx

import React, { useState } from "react";

const Counter: React.FC = () => {
    // Basic type: explicitly specify the number type
    const [count, setCount] = useState<number>(0);

    // Object type: specify the object type
    const [user, setUser] = useState<{ name: string; age: number }>({
        name: "Alice",
        age: 25
    });

    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={() => setCount(c => c + 1)}>+1</button>
            <button onClick={() => setCount(c => c - 1)}>-1</button>

            <p>User: {user.name}, {user.age}</p>
            <button onClick={() => setUser({ ...user, age: user.age + 1 })}>
Age+1
            </button>
        </div>
    );
};

export default Counter;

Running result:

Counter 组件渲染成功

Generic parameters:The T in useState<T> is the type of the state. If an initial value is provided, TypeScript can infer it automatically.


useEffect Types

useEffect also has complete type support.

src/components/DataFetcher.tsx

import React, { useState, useEffect } from "react";

// Define the user type
interface User {
    id: number;
    name: string;
}

const DataFetcher: React.FC = () => {
    // User list state
    const [users, setUsers] = useState<User[]>([]);
    // Loading state
    const [loading, setLoading] = useState<boolean>(true);
    // Error state
    const [error, setError] = useState<string | null>(null);

    useEffect(() => {
        // Simulate fetching data
        fetch("/api/users")
            .then(res => res.json())
            .then(data => {
                setUsers(data);
                setLoading(false);
            })
            .catch(err => {
                setError(err.message);
                setLoading(false);
            });
    }, []);  // Empty dependency array: run only once when the component mounts

    if (loading) return <div>Loading...</div>;
    if (error) return <div>Error: {error}</div>;

    return (
        <ul>
            {users.map(user => (
                <li key={user.id}>{user.name}</li>
            ))}
        </ul>
    );
};

export default DataFetcher;

Dependency array:The second parameter of useEffect is the dependency array. TypeScript will check whether all variables used in the callback have been declared in the array.


Event Handling

React events have dedicated type definitions.

src/components/Form.tsx

import React, { useState } from "react";

const Form: React.FC = () => {
    // State of string type
    const [name, setName] = useState<string>("");

    // Form submission event handling
    const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
        e.preventDefault();  // Prevent the form's default submission
        console.log("Submit:", name);
    };

    // Input change event handling
    const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
        setName(e.target.value);
    };

    return (
        <form onSubmit={handleSubmit}>
            <input
                type="text"
                value={name}
                onChange={handleChange}
                placeholder="Enter name"
            />
            <button type="submit">Submit</button>
        </form>
    );
};

export default Form;

Running result:

Form 组件渲染成功

Event types:React provides types for every DOM event, such as FormEvent, ChangeEvent, MouseEvent, etc.


Notes

  • React.FC:Recommended to use, to get complete type support
  • Props interface:Define Props types for each component
  • useState generics:Complex types need to be explicitly specified
  • Event types:Use the event types provided by React

Best practices:Put type definitions and components in the same file, or centrally manage them in a types directory.


Summary

TypeScript greatly improves the React development experience.

  • React.FC:Standard type for React function components
  • Props:Use interface to define component props
  • useState:Use generic parameters to specify the state type
  • useEffect:Complete type support
  • Events:Use React event types to avoid any

Suggestion:Use TypeScript directly in new projects, which can significantly reduce runtime errors.

Other Extensions