typescript-react-reviewer
SKILL.md
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 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 - React 19 new hooks (useActionState, useOptimistic, use), Server/Client Component boundaries
- antipatterns.md - Comprehensive anti-pattern catalog with fixes
- 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 Installs
2.1K
Repository
dotneet/claude-β¦ketplaceFirst Seen
Jan 21, 2026
Security Audits
Installed on
opencode1.8K
gemini-cli1.7K
codex1.7K
github-copilot1.7K
kimi-cli1.6K
amp1.6K