AI mistakes in JS and TS, and a checklist
how to tell a fix from a gag
What it is
The chapter's closer. JavaScript and TypeScript have a peculiarity of their own: here an AI has an easy way to make the check shut up. Three characters, and the error is gone without having been fixed.
Telling a fix from a gag is the main skill in this article.
Three gags to recognize
1. any
function handle(data: any) { ... }Switches checking off entirely. Everything coming out of an any the
compiler stops looking at, and the infection spreads further through the
code.
The honest replacement: unknown, which forces a check, or a proper
type.
2. as
const city = data as City;A promise to the compiler, taken apart in article 9.5. More dangerous than
any, because it looks like typed code.
When it is justified: rarely and deliberately — after a check of your own that the compiler doesn't understand, for instance. Then there should be a comment next to it saying why.
3. @ts-ignore and @ts-expect-error
// @ts-ignore
widget.render(options);Switches off checking for the next line. Always needs an explanation: if the reason isn't written down, in a month nobody will remember what is hidden here.
The other frequent mistakes
-
strictis off. Without it there are nonullchecks — the main benefit (article 9.3). -
Promise.allinstead ofallSettledwhen a partial result is wanted (article 9.2). -
forEach(async ...). Doesn't wait. Always a mistake if the result is needed. -
==instead of===, and||instead of??(article 9.1). -
Types duplicated by hand. A validation schema in one place, an interface in another — they will drift apart.
-
Code for old versions.
var,.then()instead ofawait, class components. There is more training data from that era (article 3.1, reason 3). -
A library method that doesn't exist. A hallucination (article 4.8). In TypeScript the compiler catches it — if the library has types.
A JS and TS checklist
Five steps on top of the general acceptance checklist (article 4.7).
1. Type checking
npx tsc --noEmitThe highest-value step. It catches five classes of error from article 9.5.
2. Search the diff for gags
git diff | grep -nE "\bany\b|\bas [A-Z]|ts-ignore|ts-expect-error"One command shows every place where checking is switched off. Each one must be explainable.
3. The linter
npx eslint .It catches what types can't see: ==, unused variables, forgotten
awaits, forEach with async (given the right rules).
4. Run it
npx tsx app.tsA type is no guarantee that outside data will arrive in the right shape (article 9.5). Running it is mandatory.
5. The boundary
Look at where external data enters the code: fetch, JSON.parse,
localStorage, forms. Is there a run-time check everywhere, rather than
just an as?
What to tell the AI
Check your code against the list:
- are there any, as or ts-ignore, and why
- is strict on and does tsc --noEmit pass
- is there == instead of === or || where ?? is needed
- is there a forEach with async inside
- Promise.all where a partial result is wanted
- where does data come in from outside and is it validated
Which of these are there? If none, say so.And separately, a request that saves a whole round of back-and-forth:
Fix the type errors properly. Don't use any, as or ts-ignore.
If an error can't be fixed without them — explain why, and
don't fix it.That last sentence matters: it gives the AI permission to say "I can't" instead of quietly gagging the check (articles 3.8, 4.8).
Cheat sheet
Three gags:
any,as,ts-ignore. If they appeared after "fix the types", the errors are hidden, not fixed.unknownis the honest replacement forany.Checklist:
tsc --noEmit· search the diff for gags · linter · run · the boundary.git diff | grep -E "\bany\b|\bas [A-Z]|ts-ignore"— one command for the whole diff.Types don't check external data: running it is mandatory.
Ask for fixes without gags, and allow "I can't" as an answer.