
typescript-react-reviewer
Expert code reviewer for TypeScript + React 19 applications. Use when reviewing React code, identifying anti-patterns, evaluating state management, or assessing code maintainability. Triggers: code review requests, PR reviews, React architecture evaluation, identifying code smells, TypeScript type safety checks, useEffect abuse detection, state management review.
- Installs
- 9K
- Last 24h
- —
- Trending rank
- —
- Security
- Pass
Install
Works with every agent the skills CLI supports.
npx skills add https://github.com/dotneet/claude-code-marketplace --skill typescript-react-reviewer- 01
Install
Run the command in your project. The CLI asks which agents to install for.
- 02
Describe the task
Ask your agent for something this skill covers. It loads typescript-react-reviewer automatically when relevant.
- 03
Review the result
The agent follows the SKILL.md steps, scripts and references bundled with the skill.
Security audits
Independent scans of the skill's instructions and bundled files.
SKILL.md
The instructions your agent reads when the skill is triggered.
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 |
FAQ
What does the typescript-react-reviewer skill do?
Expert code reviewer for TypeScript + React 19 applications. Use when reviewing React code, identifying anti-patterns, evaluating state management, or assessing code maintainability. Triggers: code review requests, PR reviews, React architecture evaluation, identifying code smells, TypeScript type safety checks, useEffect abuse detection, state management review.
How do I install typescript-react-reviewer?
Run npx skills add https://github.com/dotneet/claude-code-marketplace --skill typescript-react-reviewer in your project. The skills CLI detects the agents you use and copies the skill into the right folder. For Claude Code you can also place the skill folder at ~/.claude/skills/typescript-react-reviewer/ (personal) or .claude/skills/typescript-react-reviewer/ (project).
Which AI agents can use typescript-react-reviewer?
Any agent that supports the open Agent Skills format (a folder with a SKILL.md file), including Claude Code, Codex, Cursor, GitHub Copilot, Gemini CLI, Windsurf, Cline, OpenCode and more.
Is typescript-react-reviewer safe to install?
Security partners have reviewed it: Gen Agent Trust Hub passed; Socket passed; Snyk passed; Runlayer passed; ZeroLeaks passed. As with any skill, read the SKILL.md and bundled scripts before installing.
Who maintains typescript-react-reviewer?
It is published by dotneet in dotneet/claude-code-marketplace. It has 8,956 recorded installs.
More from dotneet/claude-code-marketplace
prompt-improver
dotneet/claude-code-marketplace
A skill for improving prompts by applying general LLM/agent best practices. When the user provides a prompt, this skill outputs an improved version, identifies missing information, and provides specific improvement points. Use when the user asks to "improve this prompt", "review this prompt", or "make this prompt better".
code-modularization-evaluator
dotneet/claude-code-marketplace
Open the skill to read its SKILL.md instructions.
perplexity-search
dotneet/claude-code-marketplace
Open the skill to read its SKILL.md instructions.
google-calendar
dotneet/claude-code-marketplace
Open the skill to read its SKILL.md instructions.
call-cursor-agent
dotneet/claude-code-marketplace
Open the skill to read its SKILL.md instructions.
context7
dotneet/claude-code-marketplace
Open the skill to read its SKILL.md instructions.
Popular code quality & workflow skills
grill-me
mattpocock/skills
A relentless interview to sharpen a plan or design.
improve-codebase-architecture
mattpocock/skills
Scan a codebase for deepening opportunities, present them as a visual HTML report, then grill through whichever one you pick.
handoff
mattpocock/skills
Compact the current conversation into a handoff document for another agent to pick up.
domain-modeling
mattpocock/skills
Build and sharpen a project's domain model. Use when discussing codebase terminology, writing or editing a GLOSSARY.md, or recording or editing an ADR.
codebase-design
mattpocock/skills
Shared vocabulary for designing deep modules. Use when the user wants to design or improve a module's interface, find deepening opportunities, decide where a seam goes, make code more testable or AI-navigable, or when another skill needs the deep-module vocabulary.
diagnosing-bugs
mattpocock/skills
Diagnosis loop for hard bugs and performance regressions. Use when the user says "diagnose"/"debug this", or reports something broken/throwing/failing/slow.