mcpField
T
typescript-react-reviewer

typescript-react-reviewer

github.com/dotneet测试与质量39.0k 次安装40 周前更新
代码仓库

关于 typescript-react-reviewer

typescript-react-reviewer 是面向 TypeScript 与 React 19 项目的代码审查技能,适合开发者和审查者。它按严重级别检查 Hook、状态管理、类型安全与架构问题,并提供参考清单。

主要功能

  1. 01按优先级识别问题
  2. 02检查 React 19 Hook 用法
  3. 03发现状态变更反模式
  4. 04评估 TypeScript 类型安全
  5. 05提供审查工作流与清单

适用场景

  1. 01合并前排查关键缺陷
  2. 02检查 Hook 依赖与清理逻辑
  3. 03评估组件结构和状态管理

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/dotneet/claude-code-marketplace --skill typescript-react-reviewer

安装后在 Claude Code 中输入/typescript-react-reviewer确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
antipatterns.md
checklist.md
react19-patterns.md

详细介绍

TypeScript + React 19 代码审查专家

精通 React 19 新特性、TypeScript 最佳实践、状态管理模式及常见反模式的代码审查专家。

审查优先级

🚫 严重(阻止合并)

这些问题会导致错误、内存泄漏或架构问题:

问题严重原因
使用 useEffect 处理派生状态产生额外的渲染周期、引发同步错误
useEffect 缺少清理函数内存泄漏
直接修改状态(.push()、.splice())更新静默失败
有条件地调用 Hook违反 Hook 规则
动态列表中使用 key={index}重排时状态错乱
使用 any 类型且没有说明理由绕过类型安全检查
在与 <form> 相同的组件中使用 useFormStatus始终返回 false(React 19 的 Bug)
在渲染期间创建供 use() 使用的 Promise无限循环
⚠️ 高优先级
问题影响
依赖数组不完整闭包过时、缺少更新
将 Props 类型标注为 any运行时错误
使用 useMemo/useCallback 没有充分理由增加不必要的复杂性
缺少错误边界错误体验不佳
受控输入初始化为 undefinedReact 警告
📝 架构/风格
问题建议
组件超过 300 行拆分为更小的组件
Props 逐层传递超过 2-3 层使用组合或上下文
状态离使用位置太远将状态放到使用位置附近
自定义 Hook 名称没有 use 前缀遵循命名约定

快速检测模式

滥用 useEffect(最常见的反模式)
// ❌ WRONG: Derived state in useEffect
const [firstName, setFirstName] = useState('');
const [fullName, setFullName] = useState('');
useEffect(() => {
  setFullName(firstName + ' ' + lastName);
}, [firstName, lastName]);

// ✅ CORRECT: Compute during render
const fullName = firstName + ' ' + lastName;
// ❌ WRONG: Event logic in useEffect
useEffect(() => {
  if (product.isInCart) showNotification('Added!');
}, [product]);

// ✅ CORRECT: Logic in event handler
function handleAddToCart() {
  addToCart(product);
  showNotification('Added!');
}
React 19 Hook 常见错误
// ❌ WRONG: useFormStatus in form component (always returns false)
function Form() {
  const { pending } = useFormStatus();
  return <form action={submit}><button disabled={pending}>Send</button></form>;
}

// ✅ CORRECT: useFormStatus in child component
function SubmitButton() {
  const { pending } = useFormStatus();
  return <button type="submit" disabled={pending}>Send</button>;
}
function Form() {
  return <form action={submit}><SubmitButton /></form>;
}
// ❌ WRONG: Promise created in render (infinite loop)
function Component() {
  const data = use(fetch('/api/data')); // New promise every render!
}

// ✅ CORRECT: Promise from props or state
function Component({ dataPromise }: { dataPromise: Promise<Data> }) {
  const data = use(dataPromise);
}
状态修改检测
// ❌ WRONG: Mutations (no re-render)
items.push(newItem);
setItems(items);

arr[i] = newValue;
setArr(arr);

// ✅ CORRECT: Immutable updates
setItems([...items, newItem]);
setArr(arr.map((x, idx) => idx === i ? newValue : x));
TypeScript 危险信号
// ❌ Red flags to catch
const data: any = response;           // Unsafe any
const items = arr[10];                // Missing undefined check
const App: React.FC<Props> = () => {}; // Discouraged pattern

// ✅ Preferred patterns
const data: ResponseType = response;
const items = arr[10]; // with noUncheckedIndexedAccess
const App = ({ prop }: Props) => {};  // Explicit props

审查工作流

  1. 首先扫描严重问题 - 检查“严重(阻止合并)”部分中的模式
  2. 检查 React 19 的用法 - 查看 react19-patterns.md,了解新的 API 模式
  3. 评估状态管理 - 状态是否放在合适的位置?服务端状态与客户端状态是否分离?
  4. 评估 TypeScript 安全性 - 泛型组件、可辨识联合类型、严格配置
  5. 检查可维护性 - 组件大小、Hook 设计、文件夹结构

参考文档

详细模式和示例请参阅:

  • react19-patterns.md - React 19 新 Hook(useActionState、useOptimistic、use)、服务端/客户端组件边界
  • antipatterns.md - 全面的反模式目录及修复方法
  • checklist.md - 用于彻底审查的完整代码审查清单

状态管理快速指南

数据类型方案
服务端/异步数据TanStack Query(绝不复制到本地状态)
简单的全局 UI 状态Zustand(约 1KB,无需 Provider)
细粒度派生状态Jotai(约 2.4KB)
组件局部状态useState/useReducer
表单状态React 19 useActionState
TanStack Query 反模式
// ❌ NEVER copy server data to local state
const { data } = useQuery({ queryKey: ['todos'], queryFn: fetchTodos });
const [todos, setTodos] = useState([]);
useEffect(() => setTodos(data), [data]);

// ✅ Query IS the source of truth
const { data: todos } = useQuery({ queryKey: ['todos'], queryFn: fetchTodos });

TypeScript 配置建议

{
  "compilerOptions": {
    "strict": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitReturns": true,
    "exactOptionalPropertyTypes": true
  }
}

noUncheckedIndexedAccess 非常关键——它能捕获 arr[i] 返回 undefined 的情况。

需要立即关注的危险信号

审查时,遇到以下情况请立即标记:

模式问题修复方法
eslint-disable react-hooks/exhaustive-deps掩盖闭包过时问题重构逻辑
在组件内部定义组件每次渲染都会重新挂载移到外部
对输入使用 useState(undefined)未受控组件警告使用空字符串
泛型与 React.FC 一起使用泛型推断失效使用显式 Props
在应用代码中使用聚合文件(index.ts)增加打包体积、产生循环依赖直接导入

评论

支持 Markdown