Fix TypeScript Errors
You are fixing TypeScript type errors. This command embeds strict rules to prevent "reward hacking" - patterns that make linters pass without actually fixing type safety issues.
CRITICAL: Read Before Starting
Your goal is RUNTIME TYPE SAFETY, not just passing linters.
If your fix would make the linter happy but could still crash at runtime, it's wrong.
Forbidden Patterns
These patterns are EXPLICITLY FORBIDDEN. Using them will require rework:
| Pattern | Why Forbidden | What To Do Instead |
|---|---|---|
as unknown as Type (undocumented) |
Erases all type info, defeats TypeScript | Fix the source to return correct type |
as any |
Disables type checking entirely | Use proper typing or Zod validation |
void (0 as unknown as Type) |
Tricks linter into thinking type is used | Delete the unused type |
const _var = ... (local variable) |
Suppresses unused warning | Delete the unused variable |
export type Foo (when unused elsewhere) |
Suppresses unused warning | Remove export or delete the type |
// @ts-ignore or // @ts-expect-error |
Hides real type problems | Fix the actual type error |
| Commenting out code | Dead code clutters codebase | Delete it (git has history) |
| Excluding files from tsconfig | Hides errors in those files | Include files, fix errors |
Required Approach
For Internal Code (services, models, aggregations)
Fix the SOURCE to return the correct type:
// WRONG - Casting a query result
const users = (await db.from("users").select("*")) as unknown as User[];
// CORRECT - Use the query builder's generic typing
const { data: users } = await db.from("users").select("*").returns<User[]>();
// WRONG - Casting a service result
const account = (await accountService.findById(id)) as Account;
// CORRECT - Fix the service to return the right type
const account = await accountService.findById(id); // Returns Account | null
if (account === null) throw new NotFoundError();
For External Data (API requests, webhooks, file uploads)
Validate with Zod at the boundary:
// WRONG - Trust external data
const webhook = req.body as WebhookPayload;
// CORRECT - Validate at boundary
const webhook = WebhookPayloadSchema.parse(req.body);
When Type Assertions ARE Acceptable
Type assertions are ONLY acceptable for third-party library limitations with full documentation:
// ACCEPTABLE - Third-party library type gap with documentation
// LIBRARY TYPE LIMITATION: The thirdPartyWrapper() function returns a type
// that TypeScript can't verify implements the expected interface.
// Verified at runtime that the object has the required methods.
// TODO: Remove when library updates types (tracked in TICKET-XXX)
const wrapped = thirdPartyResult as unknown as ExpectedInterface;
Requirements for acceptable assertions:
- The type error is from a THIRD-PARTY LIBRARY we don't control
- There's a detailed comment explaining WHY
- The comment explains what was verified at runtime
- There's a TODO with a tracking ticket
Process
- Understand the error: Read the TypeScript error message carefully
- Find the root cause: Why doesn't the type already match?
- Fix at the source: Change the source function/type, not the consumer
- Verify the fix: Detect the package manager and run type-check (see below)
- Run validation: Execute
/scan-reward-hackingbefore marking complete
Detecting Package Manager and Type-Check Script
First, check package.json for a type-check script. Then detect the package manager by looking for lock files:
bun.lockb->bun run type-checkpnpm-lock.yaml->pnpm type-checkyarn.lock->yarn type-checkpackage-lock.json->npm run type-check
If no lock file is found, fall back to npx tsc --noEmit.
Before Marking Complete
You MUST run these checks:
# Type check must pass (use the detected package manager)
# e.g., npm run type-check / yarn type-check / bun run type-check / pnpm type-check
# Scan for forbidden patterns (run /scan-reward-hacking command)
grep -r "as unknown as" [files-you-changed]
grep -r "void (0" [files-you-changed]
grep -r "as any" [files-you-changed]
If ANY forbidden pattern exists in your changes without proper documentation, your work is not complete.
The Golden Rule
If you need as, ask "Why doesn't the type already match?" and fix THAT.
Type assertions are a code smell. They mean either:
- The source function has wrong types (fix the source)
- External data wasn't validated (add Zod validation)
- A library has incomplete types (document and track)
Never use assertions to silence errors - fix the underlying type mismatch.