---
id: sm-typescript-react-reviewer
name: "typescript-react-reviewer"
url: https://skills.yangsir.net/skill/sm-typescript-react-reviewer
author: dotneet
domain: ai-code-generation-quality
tags: ["typescript", "react", "code-review", "frontend-testing", "type-safety"]
install_count: 7000
rating: 4.50 (101 reviews)
github: https://github.com/dotneet/claude-code-marketplace
---

# typescript-react-reviewer

> 此技能是一位TypeScript + React 19代码审查专家，深入了解React 19新特性、TypeScript最佳实践和状态管理模式。

**Stats**: 7,000 installs · 4.5/5 (101 reviews)

## Before / After 对比

### 自动化TypeScript React代码审查

## Readme

# typescript-react-reviewer

# TypeScript + React 19 Code Review Expert

Expert code reviewer with deep knowledge of React 19's new features, TypeScript best practices, state management patterns, and common anti-patterns.

## Review Priority Levels

### 🚫 Critical (Block Merge)

These issues cause bugs, memory leaks, or architectural problems:

Issue
Why It's Critical

`useEffect` for derived state
Extra render cycle, sync bugs

Missing cleanup in `useEffect`
Memory leaks

Direct state mutation (`.push()`, `.splice()`)
Silent update failures

Conditional hook calls
Breaks Rules of Hooks

`key={index}` in dynamic lists
State corruption on reorder

`any` type without justification
Type safety bypass

`useFormStatus` in same component as `<form>`
Always returns false (React 19 bug)

Promise created inside render with `use()`
Infinite loop

### ⚠️ High Priority

Issue
Impact

Incomplete dependency arrays
Stale closures, missing updates

Props typed as `any`
Runtime errors

Unjustified `useMemo`/`useCallback`
Unnecessary complexity

Missing Error Boundaries
Poor error UX

Controlled input initialized with `undefined`
React warning

### 📝 Architecture/Style

Issue
Recommendation

Component > 300 lines
Split into smaller components

Prop drilling > 2-3 levels
Use composition or context

State far from usage
Colocate state

Custom hooks without `use` prefix
Follow naming convention

## Quick Detection Patterns

### useEffect Abuse (Most Common Anti-Pattern)

```
// ❌ 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 Mistakes

```
// ❌ 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);
}

```

### State Mutation Detection

```
// ❌ 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

```
// ❌ 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

```

## Review Workflow

- **Scan for critical issues first** - Check for the patterns in "Critical (Block Merge)" section

- **Check React 19 usage** - See [react19-patterns.md](https://github.com/dotneet/claude-code-marketplace/blob/HEAD/review-tool/skills/typescript-react-reviewer/references/react19-patterns.md) for new API patterns

- **Evaluate state management** - Is state colocated? Server state vs client state separation?

- **Assess TypeScript safety** - Generic components, discriminated unions, strict config

- **Review for maintainability** - Component size, hook design, folder structure

## Reference Documents

For detailed patterns and examples:

- **[react19-patterns.md](https://github.com/dotneet/claude-code-marketplace/blob/HEAD/review-tool/skills/typescript-react-reviewer/references/react19-patterns.md)** - React 19 new hooks (useActionState, useOptimistic, use), Server/Client Component boundaries

- **[antipatterns.md](https://github.com/dotneet/claude-code-marketplace/blob/HEAD/review-tool/skills/typescript-react-reviewer/references/antipatterns.md)** - Comprehensive anti-pattern catalog with fixes

- **[checklist.md](https://github.com/dotneet/claude-code-marketplace/blob/HEAD/review-tool/skills/typescript-react-reviewer/references/checklist.md)** - Full code review checklist for thorough reviews

## State Management Quick Guide

Data Type
Solution

Server/async data
TanStack Query (never copy to local state)

Simple global UI state
Zustand (~1KB, no Provider)

Fine-grained derived state
Jotai (~2.4KB)

Component-local state
useState/useReducer

Form state
React 19 useActionState

### TanStack Query Anti-Pattern

```
// ❌ 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 Config Recommendations

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

```

`noUncheckedIndexedAccess` is critical - it catches `arr[i]` returning undefined.

## Immediate Red Flags

When reviewing, flag these immediately:

Pattern
Problem
Fix

`eslint-disable react-hooks/exhaustive-deps`
Hides stale closure bugs
Refactor logic

Component defined inside component
Remounts every render
Move outside

`useState(undefined)` for inputs
Uncontrolled warning
Use empty string

`React.FC` with generics
Generic inference breaks
Use explicit props

Barrel files (`index.ts`) in app code
Bundle bloat, circular deps
Direct imports

Weekly Installs2.9KRepository[dotneet/claude-…ketplace](https://github.com/dotneet/claude-code-marketplace)First SeenJan 21, 2026Security Audits[Gen Agent Trust HubPass](/dotneet/claude-code-marketplace/typescript-react-reviewer/security/agent-trust-hub)[SocketPass](/dotneet/claude-code-marketplace/typescript-react-reviewer/security/socket)[SnykPass](/dotneet/claude-code-marketplace/typescript-react-reviewer/security/snyk)Installed onclaude-code2.3Kopencode1.8Kgemini-cli1.8Kcodex1.8Kgithub-copilot1.8Kkimi-cli1.7K

---
*Source: https://skills.yangsir.net/skill/sm-typescript-react-reviewer*
*Markdown mirror: https://skills.yangsir.net/api/skill/sm-typescript-react-reviewer/markdown*