Back to skills
SKILL.md
Typescript React Reviewer
ASecurityExpert 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.
- 6 stars
- 0 votes
- 0 copies
- 5 views
- Added September 29, 2026
Works with
Security analysis
100/100Pro scans all 4 files and shows the line behind each finding
npx -y skills add AruNi-01/atmos --skill typescript-react-reviewer --agent claude-codeAre you the author of Typescript React Reviewer?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/aruni-01-typescript-react-reviewer)---
name: typescript-react-reviewer
version: "1.2.0"
description: "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."
---
# 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.
## Atmos Review Session Integration
When the prompt contains a `<review-agent-run>` block, the session may target either a **workspace** (isolated git worktree) or a **project** (the project's main checkout). The reviewer flow is target-agnostic β it only needs the `session`, `current_revision_guid`, and `run` GUIDs from the block β but respect the target kind if you need to read repo state (target kind is visible in the output of `atmos review session-show --session <session_guid>`).
Use the run/session metadata to create one inline comment per concrete finding:
```bash
atmos review create-comment \
--session <session_guid> \
--revision <current_revision_guid> \
--file <path> \
--side new \
--start-line <line> \
--end-line <line> \
--title "<short title>" \
--run <run_guid> \
--body-stdin <<'EOF'
Severity: P1
Issue: ...
Suggestion: ...
EOF
```
Prefer `--body-stdin` (or `--body-file <path>`) for multi-line bodies; `--body "..."` is only for short single-line text. After the review is complete, call:
```bash
atmos review set-status --run <run_guid> succeeded --summary-stdin <<'EOF'
<one-paragraph summary>
EOF
```
If the run cannot be completed, call `atmos review set-status --run <run_guid> failed --message "<reason>"`.
For the full command surface (session discovery, comment reading, run lifecycle, body-input conventions, and workspace vs project semantics), see [`references/atmos-review-cli.md`](references/atmos-review-cli.md).
## 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)
```typescript
// β 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;
```
```typescript
// β 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
```typescript
// β 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>;
}
```
```typescript
// β 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
```typescript
// β 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
```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
```
## Review Workflow
1. **Scan for critical issues first** - Check for the patterns in "Critical (Block Merge)" section
2. **Check React 19 usage** - See [react19-patterns.md](references/react19-patterns.md) for new API patterns
3. **Evaluate state management** - Is state colocated? Server state vs client state separation?
4. **Assess TypeScript safety** - Generic components, discriminated unions, strict config
5. **Review for maintainability** - Component size, hook design, folder structure
## Generate the Report
Write the review report to the specified file path. The report MUST follow this exact structure:
> **Traceability frontmatter**: When this review is run inside an Atmos review session, the prompt will include a ready-to-copy YAML frontmatter block (under the key `atmos_review`). Write that block **verbatim** as the very first lines of the report file, before the `# TypeScript + React 19 Code Review Report` heading. Do not edit, reformat, or omit any field. When there is no session context, omit the frontmatter.
Example of the frontmatter the prompt will supply:
```yaml
---
atmos_review:
session_guid: "<guid>"
run_guid: "<guid>"
base_revision_guid: "<guid>"
current_revision_guid: "<guid>"
skill_id: "typescript-react-reviewer"
generated_at: "<ISO-8601 UTC>"
---
```
```markdown
# TypeScript + React 19 Code Review Report
| Entry | Details |
| :--- | :--- |
| **Date** | YYYY-MM-DD HH:MM |
| **Reviewer** | AI (typescript-react-reviewer) |
| **Scope** | [description of what was reviewed β git diff / specific files / commit range] |
| **Project Stack** | TypeScript + React 19 (detected frameworks/libraries) |
| **Overall Assessment** | **APPROVE** \| **REQUEST_CHANGES** \| **COMMENT** |
---
## Summary
| Metric | Value |
|--------|-------|
| Files Reviewed | X |
| Lines Changed | +Y / -Z |
| Critical Issues | N |
| High Priority | N |
| Architecture Issues | N |
---
## Findings by Priority
### π« Critical
> None found. β
(or list each finding with file, line, impact, and fix)
### β οΈ High Priority
(same format)
### π Architecture/Style
(same format)
---
## Recommended Next Steps
1. Address any critical bugs (P0)
2. Refactor high-priority anti-patterns
3. Consider architectural improvements
```
## Reference Documents
For detailed patterns and examples:
- **[react19-patterns.md](references/react19-patterns.md)** - React 19 new hooks (useActionState, useOptimistic, use), Server/Client Component boundaries
- **[antipatterns.md](references/antipatterns.md)** - Comprehensive anti-pattern catalog with fixes
- **[checklist.md](references/checklist.md)** - Full code review checklist for thorough reviews
- **[atmos-review-cli.md](references/atmos-review-cli.md)** - Shared Atmos review CLI reference (symlinked from `atmos-review-fix`)
## 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
```typescript
// β 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
```json
{
"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 |
Files in this skill
- SKILL.md
- references/antipatterns.md
- references/checklist.md
- references/react19-patterns.md
Attribution
Comments
Loading commentsβ¦
Newsletter
Get the weekly list of safe new skills, and the ones we pulled.