迁移到 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
@@ -0,0 +1,108 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import {
|
||||
DndContext,
|
||||
closestCenter,
|
||||
KeyboardSensor,
|
||||
PointerSensor,
|
||||
useSensor,
|
||||
useSensors,
|
||||
DragEndEvent,
|
||||
} from '@dnd-kit/core';
|
||||
import {
|
||||
arrayMove,
|
||||
SortableContext,
|
||||
sortableKeyboardCoordinates,
|
||||
verticalListSortingStrategy,
|
||||
} from '@dnd-kit/sortable';
|
||||
import { DraggableItem } from '../components/DraggableItem';
|
||||
import {
|
||||
defaultExperiments,
|
||||
loadExperimentsFromStorage,
|
||||
saveExperimentsToStorage,
|
||||
} from '../data/experiments';
|
||||
|
||||
export default function Home() {
|
||||
const navigate = useNavigate();
|
||||
|
||||
// 从 localStorage 加载数据,如果没有则使用默认数据
|
||||
const [experiments, setExperiments] = useState(() => {
|
||||
return loadExperimentsFromStorage() || defaultExperiments;
|
||||
});
|
||||
|
||||
// 当实验数据变化时,保存到 localStorage
|
||||
useEffect(() => {
|
||||
saveExperimentsToStorage(experiments);
|
||||
}, [experiments]);
|
||||
|
||||
const sensors = useSensors(
|
||||
useSensor(PointerSensor),
|
||||
useSensor(KeyboardSensor, {
|
||||
coordinateGetter: sortableKeyboardCoordinates,
|
||||
})
|
||||
);
|
||||
|
||||
function handleDragEnd(event: DragEndEvent) {
|
||||
const { active, over } = event;
|
||||
|
||||
if (over && active.id !== over.id) {
|
||||
setExperiments((items) => {
|
||||
const oldIndex = items.findIndex((item) => item.id === active.id);
|
||||
const newIndex = items.findIndex((item) => item.id === over.id);
|
||||
return arrayMove(items, oldIndex, newIndex);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function handleExperimentClick(id: string) {
|
||||
navigate(`/experiment/${id}`);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="max-w-3xl mx-auto">
|
||||
<div className="bg-white rounded-xl shadow-lg p-6 mb-6">
|
||||
<h2 className="text-2xl font-semibold text-gray-800 mb-4">
|
||||
实验项目列表
|
||||
</h2>
|
||||
<p className="text-gray-600 mb-6">
|
||||
拖动实验项目可以调整顺序,规划您的学习路径。点击项目查看详情。
|
||||
</p>
|
||||
|
||||
<DndContext
|
||||
sensors={sensors}
|
||||
collisionDetection={closestCenter}
|
||||
onDragEnd={handleDragEnd}
|
||||
>
|
||||
<SortableContext
|
||||
items={experiments}
|
||||
strategy={verticalListSortingStrategy}
|
||||
>
|
||||
{experiments.map((experiment, index) => {
|
||||
const Icon = experiment.icon;
|
||||
return (
|
||||
<DraggableItem key={experiment.id} id={experiment.id}>
|
||||
<div
|
||||
className="flex items-center gap-4 cursor-pointer hover:bg-gray-50 rounded transition-colors p-2 -m-2"
|
||||
onClick={() => handleExperimentClick(experiment.id)}
|
||||
>
|
||||
<div className="flex-shrink-0 w-12 h-12 bg-indigo-100 rounded-full flex items-center justify-center">
|
||||
<Icon className="w-6 h-6 text-indigo-600" />
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h3 className="font-semibold text-gray-800">
|
||||
{index + 1}. {experiment.name}
|
||||
</h3>
|
||||
<p className="text-sm text-gray-600">
|
||||
{experiment.description}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</DraggableItem>
|
||||
);
|
||||
})}
|
||||
</SortableContext>
|
||||
</DndContext>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user