【react】TypeScript在react中的使用
目录
一、环境与项目配置
1. 创建 TypeScript React 项目
2. 关键tsconfig.json配置
3.安装核心类型包
二、组件类型定义
1. 函数组件(React 18+)
2.类组件
三、Hooks 的深度类型集成
1. useState
2. useEffect
3. useRef
4. 自定义 Hook
四、事件处理
1. 表单事件
2. 鼠标/键盘事件
五、状态管理(Redux Toolkit)
1.定义类型化的 Slice
2. 类型化的useSelector和useDispatch(组件中使用)
六、路由(React Router v6)
七、类型扩展与最佳实践
1. 扩展全局类型
2. 组件默认 Props
3. 泛型组件
4.高阶组件(HOC)类型
5.Context API类型安全
八、测试与调试
1. Jest + Testing Library
2.类型安全的Mock数据
九、常见问题
1. 如何处理第三方库类型?
2.处理动态导入(Lazy Loading )
3. 类型断言的使用
3. 处理可选 Props
4、性能优化
1.使用react.memo 优化渲染
2.类型化的useCallback和useMemo
十一、学习资源
一、环境与项目配置
1. 创建 TypeScript React 项目
# 使用 Create React App(推荐)
npx create-react-app my-app --template typescript
# 或使用 Vite(更轻量)
npm create vite@latest my-react-app -- --template react-ts
2. 关键tsconfig.json配置
{"compilerOptions": {"target": "ESNext","lib": ["DOM", "DOM.Iterable", "ESNext"], // 浏览器环境支持"jsx": "react-jsx", // React 17+ 的 JSX 转换"strict": true, // 启用所有严格类型检查"esModuleInterop": true, // 兼容 CommonJS/ES6 模块"skipLibCheck": true, // 跳过第三方库类型检查(提升速度)"forceConsistentCasingInFileNames": true, // 强制文件名大小写一致"baseUrl": "./src", // 路径别名基础目录"paths": {"@components/*": ["components/*"] // 路径别名配置}},"include": ["src/**/*"]
}
3.安装核心类型包
npm install @types/react @types/react-dom @types/node --save-dev
二、组件类型定义
1. 函数组件(React 18+)
// Button.tsx
import React from 'react';// 定义 Props 类型
interface ButtonProps {children: React.ReactNode;onClick: () => void;variant?: 'primary' | 'secondary';//可选属性disabled?: boolean;//可选回调函数
}//使用React.FC 泛型定义组件( React 18 后 FC 不再隐式包含 children)
const Button: React.FC<ButtonProps> = ({ children, onClick, variant = 'primary', //默认值disabled = false
}) => {return (<button className={`btn-${variant}`}onClick={onClick}disabled={disabled}>{children}</button>);
};export default Button;
2.类组件
// Counter.tsx
import React from 'react';//State和Props类型定义
interface CounterProps {initialCount?: number;
}interface CounterState {count: number;
}class Counter extends React.Component<CounterProps, CounterState> {// 默认 Propsstatic defaultProps: Partial<CounterProps> = {initialCount: 0};// 初始化 State(需明确类型)state: CounterState = {count: this.props.initialCount!};// 箭头函数绑定 this(避免手动 bind)increment = () => {this.setState((prev) => ({ count: prev.count + 1 }));};render() {return (<div><p>Count: {this.state.count}</p><button onClick={this.increment}>Increment</button></div>);}
}
三、Hooks 的深度类型集成
1. useState
//react
//const [count, setCount] = React.useState<number>(0); // 显式指定类型
//const [user, setUser] = React.useState<User | null>(null); // 联合类型// 基础类型推断
const [count, setCount] = useState<number>(0);// 复杂对象类型(明确初始值)
interface User {id: string;name: string;email?: string;
}const [user, setUser] = useState<User>({id: '1',name: 'Alice'
});
2. useEffect
// 异步请求的类型安全处理
useEffect(() => {let isMounted = true; // 防止组件卸载后更新状态const fetchData = async () => {try {const response = await fetch('/api/users');const data: User[] = await response.json();if (isMounted) setUsers(data);} catch (error) {console.error('Fetch error:', error);}};fetchData();return () => {isMounted = false;};
}, []);
3. useRef
// DOM 引用
const inputRef = useRef<HTMLInputElement>(null);
// 可变值(非 DOM)
// 引用 DOM 元素
const inputRef = useRef<HTMLInputElement>(null);// 存储可变值(非 DOM)
interface Timer {id: number;start: () => void;
}const timerRef = useRef<Timer | null>(null);
4. 自定义 Hook
// useLocalStorage.ts
import { useState, useEffect } from 'react';function useLocalStorage<T>(key: string,initialValue: T
): [T, (value: T) => void] {const [storedValue, setStoredValue] = useState<T>(() => {try {const item = window.localStorage.getItem(key);return item ? JSON.parse(item) : initialValue;} catch (error) {return initialValue;}});const setValue = (value: T) => {try {setStoredValue(value);window.localStorage.setItem(key, JSON.stringify(value));} catch (error) {console.error('LocalStorage set error:', error);}};useEffect(() => {const handleStorageChange = (e: StorageEvent) => {if (e.key === key) {setStoredValue(JSON.parse(e.newValue!));}};window.addEventListener('storage', handleStorageChange);return () => window.removeEventListener('storage', handleStorageChange);}, [key]);return [storedValue, setValue];
}// 使用
const [theme, setTheme] = useLocalStorage<'light' | 'dark'>('theme', 'light');
四、事件处理
1. 表单事件
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {e.preventDefault();// 访问表单元素const input = e.currentTarget.elements.namedItem('username') as HTMLInputElement;console.log(input.value);
};
2. 鼠标/键盘事件
const handleClick = (e: React.MouseEvent<HTMLButtonElement>) => {console.log(e.clientX, e.clientY);
};
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {if (e.key === 'Enter') {// 处理回车}
};
五、状态管理(Redux Toolkit)
1.定义类型化的 Slice
// features/counter/counterSlice.ts
import { createSlice, PayloadAction } from '@reduxjs/toolkit';interface Todo {id:string;text: string ;value: number;
}
interface TodosState {list: Todo[];status: 'idle' | 'loading' | 'succeeded' | 'failef';const initialState: TodosState = {list: [];status: 'idle'
};const counterSlice = createSlice({name: 'tods',initialState,reducers: {addTodo: (state, action: PayloadAction<{ text: string }>) => {const newTodo: Todo = {id: Date.now().toString(),text: action.payload.text,completed: false};state.list.push(newTodo);},toggleTodo: (state, action: PayloadAction<string>) => {const todo = state.list.find(t => t.id === action.payload);if (todo) todo.completed = !todo.completed;}},extraReducers: (builder) => {// 异步处理示例builder.addCase(fetchTodos.pending, (state) => {state.status = 'loading';}).addCase(fetchTodos.fulfilled, (state, action: PayloadAction<Todo[]>) => {state.status = 'succeeded';state.list = action.payload;});}
});export const {addTodo, toggleTodo} = counterSlice.actions;
export default todoSlice.reducer;
2. 类型化的useSelector和useDispatch(组件中使用)
// Counter.tsx
import { useDispatch, useSelector } from 'react-redux';
import type { RootState } from '@/app/store';
import { increment } from '@/features/counter/counterSlice';const Counter = () => {const count = useSelector((state: RootState) => state.counter.value);const dispatch = useDispatch();return (<div><span>{count}</span><button onClick={() => dispatch(increment())}>+1</button></div>);
};
六、路由(React Router v6)
// App.tsx
import { BrowserRouter, Routes, Route } from 'react-router-dom';interface RouteConfig {path: string;element: React.ReactNode;
}const routes: RouteConfig[] = [{ path: '/', element: <HomePage /> },{ path: '/about', element: <AboutPage /> }
];const App = () => (<BrowserRouter><Routes>{routes.map((route) => (<Route key={route.path} {...route} />))}</Routes></BrowserRouter>
);
七、类型扩展与最佳实践
1. 扩展全局类型
// react-app-env.d.ts
declare namespace React {interface HTMLAttributes<T> extends AriaAttributes, DOMAttributes<T> {// 扩展自定义属性customAttr?: string;}
}
2. 组件默认 Props
interface Props {size?: 'small' | 'medium' | 'large';
}const MyComponent = ({ size = 'medium' }: Props) => {// ...
};
3. 泛型组件
interface ListProps<T> {items: T[];renderItem: (item: T) => React.ReactNode;
}
function List<T>({ items, renderItem }: ListProps<T>) {return (<div>{items.map((item, index) => (<div key={index}>{renderItem(item)}</div>))}</div>);
}// 使用
<List<{ id: string; name: string }> items={users}renderItem={(user) => <span>{user.name}</span>}
/>
4.高阶组件(HOC)类型
type WithLoadingProps = {isLoading: boolean;
};// 高阶组件:为组件添加 loading 状态
function withLoading<T extends object>(WrappedComponent: React.ComponentType<T>
) {return (props: T & WithLoadingProps) => {if (props.isLoading) return <div>Loading...</div>;return <WrappedComponent {...props} />;};
}// 使用
const UserListWithLoading = withLoading(UserList);
<UserListWithLoading isLoading={true} users={[]} />;
5.Context API类型安全
// ThemeContext.tsx
import React, { createContext, useContext } from 'react';type Theme = 'light' | 'dark';
type ThemeContextType = {theme: Theme;toggleTheme: () => void;
};const ThemeContext = createContext<ThemeContextType | undefined>(undefined);export const ThemeProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {const [theme, setTheme] = useState<Theme>('light');const toggleTheme = () => {setTheme((prev) => (prev === 'light' ? 'dark' : 'light'));};return (<ThemeContext.Provider value={{ theme, toggleTheme }}>{children}</ThemeContext.Provider>);
};// 自定义 Hook 确保 Context 存在
export const useTheme = () => {const context = useContext(ThemeContext);if (!context) throw new Error('useTheme must be used within ThemeProvider');return context;
};
八、测试与调试
1. Jest + Testing Library
// Button.test.tsx
import { render, screen, fireEvent } from '@testing-library/react';
import Button from './Button';test('handles click event', () => {const handleClick = jest.fn();render(<Button onClick={handleClick}>Click Me</Button>);fireEvent.click(screen.getByText(/click me/i));expect(handleClick).toHaveBeenCalledTimes(1);
});// 测试异步操作
test('loads user data', async () => {render(<UserProfile userId="1" />);await waitFor(() => {expect(screen.getByText('Alice')).toBeInTheDocument();});
});
2.类型安全的Mock数据
// mocks/user.ts
import { User } from '../types';export const mockUser: User = {id: '1',name: 'Alice',email: 'alice@example.com'
};// 测试中使用
jest.mock('../api', () => ({fetchUser: jest.fn().mockResolvedValue(mockUser)
}));
九、常见问题
1. 如何处理第三方库类型?
npm install @types/react-router-dom @types/lodash # 安装类型声明# 安装社区维护的类型包
npm install @types/lodash @types/react-select --save-dev# 临时忽略类型检查(不推荐)
// @ts-ignore
import untypedLib from 'untyped-lib';
2.处理动态导入(Lazy Loading )
// 明确组件类型
const LazyComponent = React.lazy(() => import('./LazyComponent'));// 使用 Suspense
<Suspense fallback={<div>Loading...</div>}><LazyComponent />
</Suspense>
3. 类型断言的使用
//例a
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {const value = e.target.value as string; // 明确类型//例b
const element = document.getElementById('root') as HTMLElement; // 安全断言
const data = response as ApiResponse; // 明确知道类型时
3. 处理可选 Props
interface AvatarProps {src: string;alt?: string; // 可选属性size?: number;
}const Avatar = ({ src, alt = '', size = 40 }: AvatarProps) => (<img src={src} alt={alt} width={size} />
);
4、性能优化
1.使用react.memo 优化渲染
interface MemoizedComponentProps {data: string[];
}const MemoizedComponent = React.memo<MemoizedComponentProps>(({ data }) => {// 复杂计算return <div>{data.join(', ')}</div>;
});
2.类型化的useCallback和useMemo
const memoizedCallback = useCallback((id: string) => {console.log('Callback called with:', id);},[] // 依赖项数组
);const memoizedValue = useMemo(() => {return computeExpensiveValue(a, b);
}, [a, b]); // 依赖项变化时重新计算
十一、学习资源
-
React TypeScript Cheatsheet
-
DefinitelyTyped(第三方库类型)
-
TypeScript 官方文档
码字不易,各位大佬点点赞呗
相关文章:
【react】TypeScript在react中的使用
目录 一、环境与项目配置 1. 创建 TypeScript React 项目 2. 关键tsconfig.json配置 3.安装核心类型包 二、组件类型定义 1. 函数组件(React 18) 2.类组件 三、Hooks 的深度类型集成 1. useState 2. useEffect 3. useRef 4. 自定义 Hook 四、事…...

vllm的使用方式,入门教程
vLLM是一个由伯克利大学LMSYS组织开源的大语言模型推理框架,旨在提升实时场景下的大语言模型服务的吞吐与内存使用效率。以下是详细的vLLM使用方式和入门教程: 1. 前期准备 在开始使用vLLM之前,建议先掌握一些基础知识,包括操作…...

IDEA 使用codeGPT+deepseek
一、环境准备 1、IDEA 版本要求 安装之前确保 IDEA 处于 2023.x 及以上的较新版本。 2、Python 环境 安装 Python 3.8 或更高版本 为了确保 DeepSeek 助手能够顺利运行,您需要在操作系统中预先配置 Python 环境。具体来说,您需要安装 Python 3.8 或更高…...
vue3中测试:单元测试、组件测试、端到端测试
1、单元测试:单元测试通常适用于独立的业务逻辑、组件、类、模块或函数,不涉及 UI 渲染、网络请求或其他环境问题。 describe(increment, () > {// 测试用例 }) toBe():用于严格相等比较(),适用于原始类…...
机器学习介绍与数据集
一、机器学习介绍与定义 1.1 机器学习定义 机器学习(Machine Learning)是让计算机从数据中自动学习规律,并依据这些规律对未来数据进行预测的技术。它涵盖聚类、分类、决策树、贝叶斯、神经网络、深度学习(Deep Learning…...

React 源码揭秘 | 更新队列
前面几篇遇到updateQueue的时候,我们把它先简单的当成了一个队列处理,这篇我们来详细讨论一下这个更新队列。 有关updateQueue中的部分,可以见源码 UpdateQueue实现 Update对象 我们先来看一下UpdateQueue中的内容,Update对象&…...

关于网络端口探测:TCP端口和UDP端口探测区别
网络端口探测是网络安全领域中的一项基础技术,它用于识别目标主机上开放的端口以及运行在这些端口上的服务。这项技术对于网络管理和安全评估至关重要。在网络端口探测中,最常用的两种协议是TCP(传输控制协议)和UDP(用…...
Vue.js 中使用 JSX 自定义语法封装组件
Vue.js 中使用 JSX 自定义语法封装组件 在 Vue.js 开发中,使用模板语法是常见的构建用户界面方式,但对于一些开发者,特别是熟悉 JavaScript 语法的,JSX 提供了一种更灵活、更具表现力的替代方案。通过 JSX,我们可以在…...
设计模式教程:备忘录模式(Memento Pattern)
备忘录模式(Memento Pattern)详解 一、模式概述 备忘录模式(Memento Pattern)是一种行为型设计模式,允许在不暴露对象实现细节的情况下,保存对象的内部状态,并在需要时恢复该状态。备忘录模式…...
使用 C# 以api的形式调用 DeepSeek
一:创建 API 密钥 首先,您需要来自 DeepSeek 的 API 密钥。访问 DeepSeek,创建一个帐户,并生成一个新的 API 密钥。 二:安装所需的 NuGet 包 使用 NuGet 包管理器安装包,或在包管理器控制台中运行以下命…...

CS5366AN:高集成Type-C转HDMI 4K60Hz芯片的国产突破
一、芯片概述 CS5366AN 是集睿致远(ASL)推出的一款高度集成的 Type-C转HDMI 2.0视频转换芯片,专为扩展坞、游戏底座、高清显示设备等场景设计。其核心功能是将USB Type-C接口的DisplayPort信号(DP Alt Mode)转换为HDM…...

瑞芯微RK安卓Android主板GPIO按键配置方法,触觉智能嵌入式开发
触觉智能分享,瑞芯微RK安卓Android主板GPIO按键配置方法,方便大家更好利用空闲IO!由触觉智能Purple Pi OH鸿蒙开发板演示,搭载了瑞芯微RK3566四核处理器,树莓派卡片电脑设计,支持安卓Android、开源鸿蒙Open…...

Dify自定义工作流集成指南:对接阿里云百炼文生图API的实现方案
dify工作流的应用基本解释 dify应用发布相关地址:应用发布 | Dify 根据官方教程,我们可以看到dify自定义的工作流可以发布为----工具 这个教程将介绍如何通过工作流建立一个使用阿里云百炼文生图模型。 工具则可以给其他功能使用,如agent…...
前端项目配置 Nginx 全攻略
在前端开发中,项目开发完成后,如何高效、稳定地将其部署到生产环境是至关重要的一步。Nginx 作为一款轻量级、高性能的 Web 服务器和反向代理服务器,凭借其出色的性能和丰富的功能,成为了前端项目部署的首选方案。本文将详细介绍在…...
基于开源鸿蒙(OpenHarmony)的【智能家居综合应用】系统
基于开源鸿蒙OpenHarmony的智能家居综合应用系统 1. 智能安防与门禁系统1) 系统概述2) 系统架构3)关键功能实现4)安全策略5)总结 2.环境智能调节系统1)场景描述2)技术实现3)总结 3.健康管理与睡眠监测1&…...

电子电气架构 --- 主机厂电子电气架构演进
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 简单,单纯,喜欢独处,独来独往,不易合同频过着接地气的生活,除了生存温饱问题之外,没有什么过多的欲望,表面看起来很高冷,内心热情,如果你身…...

物联网通信应用案例之《智慧农业》
案例概述 在智慧农业方面,一般的应用场景为可以自动检测温度湿度等一系列环境情况并且可以自动做出相应的处理措施如简单的浇水和温度控制等,且数据情况可远程查看,以及用户可以实现远程控制。 基本实现原理 传感器通过串口将数据传递到Wi…...

Java注解的原理
目录 问题: 作用: 原理: 注解的限制 拓展: 问题: 今天刷面经,发现自己不懂注解的原理,特此记录。 作用: 注解的作用主要是给编译器看的,让它帮忙生成一些代码,或者是帮忙检查…...
AI知识架构之神经网络
神经网络:这是整个内容的主题,是一种模拟人类大脑神经元结构和功能的计算模型,在人工智能领域广泛应用。基本概念:介绍神经网络相关的基础概念,为后续深入理解神经网络做铺垫。定义与起源: 神经网络是模拟人类大脑神经元结构和功能的计算模型,其起源于对生物神经系统的研…...

OpenGL 04--GLSL、数据类型、Uniform、着色器类
一、着色器 在 OpenGL 中,着色器(Shader)是运行在 GPU 上的程序,用于处理图形渲染管线中的不同阶段。 这些小程序为图形渲染管线的某个特定部分而运行。从基本意义上来说,着色器只是一种把输入转化为输出的程序。着色器…...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

springboot 百货中心供应链管理系统小程序
一、前言 随着我国经济迅速发展,人们对手机的需求越来越大,各种手机软件也都在被广泛应用,但是对于手机进行数据信息管理,对于手机的各种软件也是备受用户的喜爱,百货中心供应链管理系统被用户普遍使用,为方…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
c++ 面试题(1)-----深度优先搜索(DFS)实现
操作系统:ubuntu22.04 IDE:Visual Studio Code 编程语言:C11 题目描述 地上有一个 m 行 n 列的方格,从坐标 [0,0] 起始。一个机器人可以从某一格移动到上下左右四个格子,但不能进入行坐标和列坐标的数位之和大于 k 的格子。 例…...

C# 类和继承(抽象类)
抽象类 抽象类是指设计为被继承的类。抽象类只能被用作其他类的基类。 不能创建抽象类的实例。抽象类使用abstract修饰符声明。 抽象类可以包含抽象成员或普通的非抽象成员。抽象类的成员可以是抽象成员和普通带 实现的成员的任意组合。抽象类自己可以派生自另一个抽象类。例…...

令牌桶 滑动窗口->限流 分布式信号量->限并发的原理 lua脚本分析介绍
文章目录 前言限流限制并发的实际理解限流令牌桶代码实现结果分析令牌桶lua的模拟实现原理总结: 滑动窗口代码实现结果分析lua脚本原理解析 限并发分布式信号量代码实现结果分析lua脚本实现原理 双注解去实现限流 并发结果分析: 实际业务去理解体会统一注…...

Docker 本地安装 mysql 数据库
Docker: Accelerated Container Application Development 下载对应操作系统版本的 docker ;并安装。 基础操作不再赘述。 打开 macOS 终端,开始 docker 安装mysql之旅 第一步 docker search mysql 》〉docker search mysql NAME DE…...
A2A JS SDK 完整教程:快速入门指南
目录 什么是 A2A JS SDK?A2A JS 安装与设置A2A JS 核心概念创建你的第一个 A2A JS 代理A2A JS 服务端开发A2A JS 客户端使用A2A JS 高级特性A2A JS 最佳实践A2A JS 故障排除 什么是 A2A JS SDK? A2A JS SDK 是一个专为 JavaScript/TypeScript 开发者设计的强大库ÿ…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

消防一体化安全管控平台:构建消防“一张图”和APP统一管理
在城市的某个角落,一场突如其来的火灾打破了平静。熊熊烈火迅速蔓延,滚滚浓烟弥漫开来,周围群众的生命财产安全受到严重威胁。就在这千钧一发之际,消防救援队伍迅速行动,而豪越科技消防一体化安全管控平台构建的消防“…...