AI Slop in React and TypeScript: 10 Patterns to Catch Before Merge
Ten patterns coding agents leave in React and TypeScript that pass tsc but still need fixing, with the rule that flags each.
Ten patterns coding agents often leave in React and TypeScript, each with a cleaner version and the aislop rule that flags it. Most satisfy the type checker cheaply while the behavior goes wrong.
For the language-neutral list, see 20 AI slop code examples.
Silencing the type checker
1. as any and as unknown as
// slop
const user = (await res.json()) as any;
const order = response as unknown as Order;
// clean: validate at the boundary
const user = UserSchema.parse(await res.json());A cast turns off checking where data is least trustworthy, such as network responses. Validate
unknown input once with Zod, Valibot or a type guard. Rules: ai-slop/unsafe-type-assertion
and ai-slop/double-type-assertion. See
unsafe type assertion
and double type assertion.
2. @ts-ignore to make the build pass
// @ts-ignore
onChange(event.target.value, index);The error is still there, just hidden. If you must suppress, use
@ts-expect-error with a reason, so it fails once the issue is fixed. Rule: ai-slop/ts-directive. See
TS directive.
3. Re-coercing values that are already typed
function formatId(id: string) {
return String(id).trim();
}The parameter is already a string, so String(id) does nothing. Trust
the type, or validate earlier. Rule: ai-slop/redundant-type-coercion.
4. The same type, declared twice
// src/api/types.ts
export type User = { id: string; email: string };
// src/components/UserCard.tsx
export type User = { id: string; email: string };The two copies drift apart the first time one changes. Import the existing declaration. Rule:
ai-slop/duplicate-type-declaration.
Error handling that hides failures
5. Catch, log, continue
// slop
try {
await saveDraft(draft);
} catch (error) {
console.error("Failed to save draft");
}
setStatus("saved");The UI says “saved” even when the save failed, and the log drops the error. Show the failure or
let it reach an error boundary. Rule: ai-slop/silent-recovery, which flags catch blocks that
log without the caught error and carry on.
See swallowed exception.
6. try/catch that only rethrows
try {
return await fetchOrders(userId);
} catch (error) {
throw error;
}Six lines that do what one does. Remove it, or add context, cleanup or recovery. Rule: ai-slop/redundant-try-catch.
7. A catch that returns a safe-looking default
async function loadInvoices(accountId: string): Promise<Invoice[]> {
try {
return await api.invoices(accountId);
} catch {
return [];
}
}This tells a customer they have no invoices when the billing API is down. Decide whether failure is
a valid empty state or an error, and let the caller tell them apart. Rule:
ai-slop/hidden-fallback, a review prompt rather than a defect, since the
default is sometimes right.
React-specific problems
8. useEffect with the wrong dependencies
useEffect(() => {
fetchResults(query).then(setResults);
}, []); // query changes are ignoredResults go stale when the query changes. Agents often empty the array to stop a re-render loop instead of fixing it. aislop turns on the react-hooks lint rules for React projects, which flag this.
9. dangerouslySetInnerHTML for convenience
<div dangerouslySetInnerHTML={{ __html: comment.body }} />A cross-site scripting hole when the HTML comes from a user. Render text as text, or sanitize it
with a proper library. Rule:
security/dangerously-set-innerhtml.
10. Leftovers: console.log, unused imports, unused exports
import { useMemo, useCallback, useRef } from "react"; // only useRef used
console.log("cart state", cart);
export function formatCartLegacy(cart: Cart) { /* nothing imports this */ }Rules: ai-slop/console-leftover
and ai-slop/unused-import, plus knip for unused files and exports.
aislop fix removes the unused imports.
See console leftover
and unused import.
Scan a React or TypeScript project
npx aislop scan # or bunx / pnpm dlx
npx aislop scan --changes # only what changed
npx aislop fix # safe, mechanical fixesaislop also runs Biome, oxlint, knip, a complexity check and npm audit
or pnpm audit, and adjusts lint defaults for Next.js, React, Vite, Remix,
Astro and Expo. Imports missing from package.json are flagged as
ai-slop/hallucinated-import, with path aliases and workspaces resolved.
See supported languages.
Hand the judgment calls back to your agent, and give it rules and a hook so it writes fewer of them: Claude Code, Cursor, Codex. For Python, see AI slop in Python.
Frequently asked questions
What does AI slop look like in TypeScript?
Casts like as any and as unknown as, @ts-ignore, catch blocks that log and continue or return a safe-looking default, try/catch that only rethrows, redundant coercion, duplicated types, leftover console.log calls, and unused imports and exports.
Why do coding agents use as any so often?
The agent usually wants the error gone within the turn, and a cast does that instantly. A proper fix may mean changing a signature or schema in another file, so the cast wins unless something flags it.
Doesn't ESLint or the TypeScript compiler catch this?
Mostly not, because the patterns are valid TypeScript. aislop runs Biome, oxlint (with react-hooks and jsx-a11y rules for React) and knip, then adds AI slop rules for the shapes those tools accept.
How do I scan a React or Next.js project for AI slop?
Run npx aislop scan from the project root. It detects Next.js, React, Vite, Remix, Astro and Expo and applies matching lint defaults.
Can aislop fix these automatically?
aislop fix handles mechanical ones such as unused and duplicate imports. Casts, duplicated types and error handling need judgment, so aislop fix --claude, --cursor or --codex hands them to your coding agent with file and line.