Skip to main content
← Blog
Pattern Guide3 min read

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 ignored

Results 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 fixes

aislop 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.

All posts