mcpField
T
typescript-react-reviewer

typescript-react-reviewer

github.com/dotneetテスト・品質39.0k 回インストール40 週間前に更新
リポジトリ

typescript-react-reviewer について

typescript-react-reviewer は、TypeScript と React 19 のプロジェクト向けコードレビュー技能です。開発者やレビュアーが、フック、状態管理、型安全性、設計上の問題を優先度別に確認でき、チェックリストも参照できます。

主な機能

  1. 01優先度別の問題判定
  2. 02React 19 フックの使用確認
  3. 03状態変更のアンチパターン検出
  4. 04TypeScript の型安全性評価
  5. 05レビュー手順とチェックリスト

活用シーン

  1. 01マージ前の重大な問題の確認
  2. 02フックの依存配列とクリーンアップ確認
  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())更新の失敗に気づけない
条件付きフック呼び出しRules of Hooks に違反
動的リストでの key={index}並べ替え時に状態が破損
正当な理由のない any 型型安全性が損なわれる
<form> と同じコンポーネント内での useFormStatus常に false を返す(React 19 のバグ)
use() でレンダー中に Promise を作成無限ループ
⚠️ 優先度:高
問題影響
依存配列が不完全古いクロージャー、更新漏れ
any 型の Props実行時エラー
正当な理由のない useMemo/useCallback不必要な複雑さ
Error Boundary の不足エラー発生時の UX が悪化
undefined で初期化された制御入力React の警告
📝 アーキテクチャ/スタイル
問題推奨事項
コンポーネントが 300 行を超える小さなコンポーネントに分割
Props のバケツリレーが 2~3 階層を超えるコンポジションまたはコンテキストを使用
状態が使用箇所から遠い状態を使用箇所の近くに配置
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 のフックに関する誤り
// ❌ 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 の使用方法を確認する - 新しい API パターンについては react19-patterns.md を参照します
  3. 状態管理を評価する - 状態は使用箇所の近くにありますか? サーバー状態とクライアント状態を分離していますか?
  4. TypeScript の安全性を評価する - ジェネリックコンポーネント、判別可能なユニオン、厳格な設定を確認します
  5. 保守性を確認する - コンポーネントのサイズ、フックの設計、フォルダー構成を確認します

参考ドキュメント

詳細なパターンと例については、以下を参照してください。

  • react19-patterns.md - React 19 の新しいフック(useActionState、useOptimistic、use)、サーバー/クライアントコンポーネントの境界
  • antipatterns.md - 修正方法を含む、包括的なアンチパターンカタログ
  • checklist.md - 詳細なレビュー向けの完全なコードレビューチェックリスト

状態管理のクイックガイド

データの種類解決策
サーバー/非同期データTanStack Query(ローカル状態にコピーしない)
シンプルなグローバル UI 状態Zustand(約 1 KB、Provider 不要)
細粒度の派生状態Jotai(約 2.4 KB)
コンポーネントローカル状態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)バンドル肥大化、循環依存直接インポート

コメント