| name | typescript-code-review |
| description | TypeScript and React code review guidelines (type safety, React patterns, performance). Auto-loads when reviewing TypeScript/React code. |
| user-invocable | false |
TypeScript/React Code Review Patterns
This skill provides TypeScript and React-specific code review guidelines. Use alongside typescript-style for comprehensive review.
Critical Security Issues
XSS Vulnerabilities
<div dangerouslySetInnerHTML={{ __html: userInput }} />
element.innerHTML = userContent;
import DOMPurify from 'dompurify';
<div dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(userInput) }} />
<div>{userContent}</div>
Insecure Data Exposure
console.log("User data:", user);
console.log("Request:", request.headers);
throw new Error(`Auth failed for ${credentials}`);
console.log("User ID:", user.id);
Unsafe eval/Function Constructor
eval(userInput);
new Function(userInput)();
setTimeout(userInput, 1000);
setTimeout(() => { processInput(userInput); }, 1000);
Missing CSRF Protection
fetch('/api/delete', { method: 'POST', body: data });
fetch('/api/delete', {
method: 'POST',
headers: { 'X-CSRF-Token': csrfToken },
body: data,
});
High Priority Type Safety Issues
Unsafe Type Assertions
const user = data as User;
const items = response as any[];
function isUser(data: unknown): data is User {
return typeof data === 'object' && data !== null && 'id' in data;
}
if (isUser(data)) {
}
Non-null Assertion Abuse
const name = user!.profile!.name!;
const name = user?.profile?.name ?? 'Unknown';
if (user?.profile?.name) {
const name = user.profile.name;
}
Missing Error Handling in Async Code
async function fetchData() {
const response = await fetch(url);
return response.json();
}
async function fetchData() {
try {
const response = await fetch(url);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
} catch (error) {
console.error('Fetch failed:', error);
throw error;
}
}
Ignoring Promise Results
saveUser(userData);
await saveUser(userData);
saveUser(userData).catch(console.error);
React Anti-Patterns
Missing useEffect Dependencies
useEffect(() => {
fetchUser(userId);
}, []);
useEffect(() => {
fetchUser(userId);
}, [userId]);
State Updates on Unmounted Components
useEffect(() => {
fetchData().then(setData);
}, []);
useEffect(() => {
let mounted = true;
fetchData().then((data) => {
if (mounted) setData(data);
});
return () => { mounted = false; };
}, []);
useEffect(() => {
const controller = new AbortController();
fetch(url, { signal: controller.signal })
.then(res => res.json())
.then(setData)
.catch(err => {
if (err.name !== 'AbortError') throw err;
});
return () => controller.abort();
}, [url]);
Missing Key Prop in Lists
items.map((item, index) => <Item key={index} data={item} />)
items.map((item) => <Item key={item.id} data={item} />)
Inline Functions in JSX (Performance)
<Button onClick={() => handleClick(id)} />
const handleButtonClick = useCallback(() => handleClick(id), [id]);
<MemoizedButton onClick={handleButtonClick} />
Props Drilling Deep
<App user={user}>
<Layout user={user}>
<Sidebar user={user}>
<UserProfile user={user} />
// BETTER - use Context for cross-cutting concerns
const UserContext = createContext<User | null>(null);
<UserContext.Provider value={user}>
<App />
</UserContext.Provider>
Performance Anti-Patterns
Re-rendering Entire Lists
function ItemList({ items }: { items: Item[] }) {
return items.map(item => <ItemRow item={item} />);
}
const MemoizedItemRow = memo(ItemRow);
function ItemList({ items }: { items: Item[] }) {
return items.map(item => <MemoizedItemRow key={item.id} item={item} />);
}
Expensive Calculations Without Memoization
function ExpensiveComponent({ data }: { data: number[] }) {
const sorted = [...data].sort((a, b) => a - b);
const sum = data.reduce((a, b) => a + b, 0);
return <div>{sorted.join(',')}: {sum}</div>;
}
function ExpensiveComponent({ data }: { data: number[] }) {
const sorted = useMemo(() => [...data].sort((a, b) => a - b), [data]);
const sum = useMemo(() => data.reduce((a, b) => a + b, 0), [data]);
return <div>{sorted.join(',')}: {sum}</div>;
}
Unnecessary State
const [items, setItems] = useState<Item[]>([]);
const [itemCount, setItemCount] = useState(0);
setItems(newItems);
setItemCount(newItems.length);
const [items, setItems] = useState<Item[]>([]);
const itemCount = items.length;
Large Bundle Imports
import _ from 'lodash';
import moment from 'moment';
import debounce from 'lodash/debounce';
import { format } from 'date-fns';
Accessibility Issues
Missing ARIA Labels
<button onClick={onClose}>
<CloseIcon />
</button>
<button onClick={onClose} aria-label="Close dialog">
<CloseIcon />
</button>
Non-Interactive Elements with Handlers
<div onClick={handleClick}>Click me</div>
<button onClick={handleClick}>Click me</button>
<div
role="button"
tabIndex={0}
onClick={handleClick}
onKeyDown={(e) => e.key === 'Enter' && handleClick()}
>
Click me
</div>
Missing Form Labels
<input type="email" placeholder="Email" />
<label>
Email
<input type="email" />
</label>
<label htmlFor="email">Email</label>
<input id="email" type="email" />
Color-Only Indicators
<span style={{ color: isError ? 'red' : 'green' }}>
{status}
</span>
<span style={{ color: isError ? 'red' : 'green' }}>
{isError ? '❌ ' : '✓ '}{status}
</span>
Common TypeScript Mistakes
Improper Null Checking
if (!value) return;
if (value == null) return;
if (value === null || value === undefined) return;
Object Spread Overwrites
const config = { ...defaultConfig, ...userConfig, timeout: 5000 };
const config = { timeout: 5000, ...defaultConfig, ...userConfig };
Array Method Return Values
const doubled = items.forEach(x => x * 2);
const doubled = items.map(x => x * 2);
const active = items.filter(item => item.status);
const active = items.filter(item => item.status === 'active');
Test Coverage Gaps
Flag missing tests for:
- Error states: Network failures, invalid inputs, edge cases
- User interactions: Button clicks, form submissions, keyboard navigation
- Async behavior: Loading states, success/error handling
- Accessibility: Screen reader compatibility, keyboard navigation
- Edge cases: Empty arrays, null values, boundary conditions
it('should show error message on fetch failure', async () => {});
it('should be keyboard navigable', () => {});
it('should handle empty item list', () => {});
it('should show loading state while fetching', () => {});
Code Review Checklist
Security
Type Safety
React Patterns
Performance
Accessibility