本文将通过真实 React 组件示例,系统讲解如何在 React 中正确使用 TypeScript, 重点放在组件 Props、Hooks 类型、工程实践方式,而不是零散语法。
一、为什么 React 项目一定要配 TypeScript?
在 React 项目中,以下问题极为常见:
- Props 传错字段,但运行时才发现
- 组件被错误使用,却没有任何提示
- 重构组件时,不知道哪些地方会受影响
TypeScript 在 React 中的核心价值:
- Props 变成可校验的契约
- 组件使用方式一目了然
- Hooks 返回值类型清晰
- 重构时 IDE 自动兜底
二、准备工作:创建 TypeScript React 项目
方式一:使用 Vite(推荐)
npm create vite@latest my-app -- --template react-ts
cd my-app
npm install
npm run dev
目录结构示例
src/
├── components/
│ └── Header.tsx
├── App.tsx
├── main.tsx
注意:React + TS 中,组件文件使用 .tsx 后缀。
三、第一个 TypeScript React 组件
1. 最简单的函数组件
function Hello() {
return "Hello TypeScript + React";
}
export default Hello;
此时没有任何类型,但 TypeScript 已能推断 JSX 返回值。
四、Props 的正确类型定义方式(重点)
1. 用 interface 定义 Props
interface HeaderProps {
title: string;
subtitle?: string;
}
2. 在组件中使用 Props
function Header(props: HeaderProps) {
const { title, subtitle } = props;
return (
<header>
<h1>{title}</h1>
{subtitle && <p>{subtitle}</p>}
</header>
);
}
export default Header;
3. 使用组件(IDE 会自动提示)
<Header title="首页" subtitle="欢迎使用 TypeScript" />
收益:
- 漏传
title会直接报错 - 传多余字段会提示不合法
- 组件即文档
五、React.FC 要不要用?
不推荐写法
const Header: React.FC<HeaderProps> = ({ title }) => {
return <h1>{title}</h1>;
};
推荐写法
function Header({ title }: HeaderProps) {
return <h1>{title}</h1>;
}
原因:
React.FC会隐式带上children- 对初学者不友好
- 社区已逐步不推荐
六、useState 的 TypeScript 用法
1. 自动类型推断(最常见)
const [count, setCount] = useState(0);
TypeScript 会自动推断 count 为 number。
2. 显式声明类型(复杂状态)
interface User {
id: number;
name: string;
}
const [user, setUser] = useState<User | null>(null);
七、useEffect 的类型认知
useEffect(() => {
console.log("组件挂载");
}, []);
注意:
useEffect回调不能直接声明为async- 返回值只能是清理函数或
void
八、事件处理的类型写法
1. 输入框 change 事件
function handleChange(e: React.ChangeEvent<HTMLInputElement>) {
console.log(e.target.value);
}
2. 按钮点击事件
function handleClick(e: React.MouseEvent<HTMLButtonElement>) {
console.log("clicked");
}
九、一个完整的 TS + React 示例
import { useState } from "react";
interface CounterProps {
initialValue?: number;
}
function Counter({ initialValue = 0 }: CounterProps) {
const [count, setCount] = useState(initialValue);
return (
<div>
<p>当前值:{count}</p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}
export default Counter;
这个组件同时体现了:
- Props 类型定义
- useState 类型推断
- 默认 Props
十、React + TypeScript 常见误区
- 为了省事使用
any - Props 不抽接口,直接内联写类型
- useState 初始值写错导致类型混乱
- 关闭 strict 模式“先跑起来”
十一、实践建议(非常重要)
- 组件先设计 Props,再写 JSX
- 状态复杂时,一定定义接口
- 让 TypeScript 报错,而不是绕过它
- 把组件当成“有类型的函数”
结语
TypeScript + React 的真正威力,在于“约束协作”。
当组件数量增加、参与者变多时,类型系统会成为最可靠的工程保障。
一旦你习惯了这种方式,就很难再回到“无类型 React”。