迁移到 TypeScript
完整的 TypeScript 迁移,提升代码质量和开发体验 **安装依赖:** - TypeScript 5.9.3 - @types/react, @types/react-dom, @types/node - typescript-eslint 相关包 **配置文件:** - 创建 tsconfig.json (应用配置) - 创建 tsconfig.node.json (Node 配置) - 更新 eslint.config.ts 支持 TypeScript - 所有配置文件迁移到 .ts 扩展名 **源代码迁移:** - 所有 .jsx 文件 → .tsx - 所有 .js 文件 → .ts - 添加完整的类型定义和接口 - 修复所有类型错误 **类型定义:** - Experiment 接口 (实验数据类型) - DraggableItemProps 接口 - 函数参数类型注解 - React 组件 Props 类型 **代码优化:** - 修复 main.tsx 中的 null 检查 - 添加 DragEndEvent 类型 - 使用类型守卫和类型断言 - 改进错误处理 **构建脚本:** - 添加 typecheck 脚本 - build 脚本包含类型检查 - 更新 index.html 入口为 main.tsx **验证:** - ✅ TypeScript 编译通过 - ✅ ESLint 检查通过 - ✅ 所有类型正确推导 - ✅ 代码质量提升 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
1 parent
5e84020b44
commit
543cecf2ee
21 files changed
+533
-63
No files matched your search
@@ -1,5 +1,5 @@
|
||||
import { RouterProvider } from 'react-router-dom';
|
||||
import router from './router.jsx';
|
||||
import router from './router/router';
|
||||
|
||||
function App() {
|
||||
return <RouterProvider router={router} />;
|
||||
@@ -1,8 +1,14 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { useSortable } from '@dnd-kit/sortable';
|
||||
import { CSS } from '@dnd-kit/utilities';
|
||||
import { GripVertical } from 'lucide-react';
|
||||
|
||||
export function DraggableItem({ id, children }) {
|
||||
interface DraggableItemProps {
|
||||
id: string;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
export function DraggableItem({ id, children }: DraggableItemProps) {
|
||||
const {
|
||||
attributes,
|
||||
listeners,
|
||||
@@ -1,6 +1,17 @@
|
||||
import { LucideIcon } from 'lucide-react';
|
||||
import { Thermometer, Gauge, Radio, Zap, Droplets } from 'lucide-react';
|
||||
|
||||
export const defaultExperiments = [
|
||||
/**
|
||||
* 实验项目接口
|
||||
*/
|
||||
export interface Experiment {
|
||||
id: string;
|
||||
name: string;
|
||||
icon: LucideIcon;
|
||||
description: string;
|
||||
}
|
||||
|
||||
export const defaultExperiments: Experiment[] = [
|
||||
{
|
||||
id: '1',
|
||||
name: '温度传感器实验',
|
||||
@@ -38,17 +49,17 @@ const STORAGE_KEY = 'sensor-lab-experiments';
|
||||
|
||||
/**
|
||||
* 从 localStorage 加载实验数据
|
||||
* @returns {Array} 返回保存的实验顺序,如果没有保存则返回 null
|
||||
* @returns 返回保存的实验顺序,如果没有保存则返回 null
|
||||
*/
|
||||
export const loadExperimentsFromStorage = () => {
|
||||
export const loadExperimentsFromStorage = (): Experiment[] | null => {
|
||||
try {
|
||||
const stored = localStorage.getItem(STORAGE_KEY);
|
||||
if (stored) {
|
||||
const storedIds = JSON.parse(stored);
|
||||
const storedIds = JSON.parse(stored) as string[];
|
||||
// 根据保存的 ID 顺序重新排列实验数据
|
||||
const orderedExperiments = storedIds
|
||||
.map((id) => defaultExperiments.find((exp) => exp.id === id))
|
||||
.filter(Boolean); // 过滤掉可能不存在的项目
|
||||
.filter((exp): exp is Experiment => exp !== undefined);
|
||||
|
||||
// 如果顺序数量匹配,返回排序后的数据
|
||||
if (orderedExperiments.length === defaultExperiments.length) {
|
||||
@@ -63,9 +74,9 @@ export const loadExperimentsFromStorage = () => {
|
||||
|
||||
/**
|
||||
* 保存实验数据到 localStorage
|
||||
* @param {Array} experiments - 实验数据数组
|
||||
* @param experiments - 实验数据数组
|
||||
*/
|
||||
export const saveExperimentsToStorage = (experiments) => {
|
||||
export const saveExperimentsToStorage = (experiments: Experiment[]): void => {
|
||||
try {
|
||||
const ids = experiments.map((exp) => exp.id);
|
||||
localStorage.setItem(STORAGE_KEY, JSON.stringify(ids));
|
||||
@@ -1,10 +0,0 @@
|
||||
import { StrictMode } from 'react'
|
||||
import { createRoot } from 'react-dom/client'
|
||||
import './index.css'
|
||||
import App from './App.jsx'
|
||||
|
||||
createRoot(document.getElementById('root')).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</StrictMode>,
|
||||
)
|
||||
@@ -0,0 +1,15 @@
|
||||
import { StrictMode } from 'react';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
|
||||
const rootElement = document.getElementById('root');
|
||||
if (!rootElement) {
|
||||
throw new Error('Root element not found');
|
||||
}
|
||||
|
||||
createRoot(rootElement).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
</StrictMode>
|
||||
);
|
||||
File renamed without changes.
@@ -7,6 +7,7 @@ import {
|
||||
PointerSensor,
|
||||
useSensor,
|
||||
useSensors,
|
||||
DragEndEvent,
|
||||
} from '@dnd-kit/core';
|
||||
import {
|
||||
arrayMove,
|
||||
@@ -41,7 +42,7 @@ export default function Home() {
|
||||
})
|
||||
);
|
||||
|
||||
function handleDragEnd(event) {
|
||||
function handleDragEnd(event: DragEndEvent) {
|
||||
const { active, over } = event;
|
||||
|
||||
if (over && active.id !== over.id) {
|
||||
@@ -53,7 +54,7 @@ export default function Home() {
|
||||
}
|
||||
}
|
||||
|
||||
function handleExperimentClick(id) {
|
||||
function handleExperimentClick(id: string) {
|
||||
navigate(`/experiment/${id}`);
|
||||
}
|
||||
|
||||
File renamed without changes.
File renamed without changes.
@@ -1,8 +1,8 @@
|
||||
import { createBrowserRouter } from 'react-router-dom';
|
||||
import Layout from './pages/Layout';
|
||||
import Home from './pages/Home';
|
||||
import ExperimentDetail from './pages/ExperimentDetail';
|
||||
import NotFound from './pages/NotFound';
|
||||
import Layout from '../pages/Layout';
|
||||
import Home from '../pages/Home';
|
||||
import ExperimentDetail from '../pages/ExperimentDetail';
|
||||
import NotFound from '../pages/NotFound';
|
||||
|
||||
/**
|
||||
* 应用路由配置
|
||||
Reference in new issue
Block a user