chore(lint): warn on type-erasing assertions (as any/never/unknown) via Biome plugin#624
Conversation
Adds `biome-plugins/no-type-erasing-assertions.grit`, wired into biome.json, that warns on `as any` / `as never` / `as unknown` in source — assertions that punch through the type system instead of narrowing (a real mismatch can hide behind them). `as const`, plain `as SpecificType`, and `never` as a type annotation are NOT flagged. `as unknown` also catches the inner half of an `as unknown as T` double-cast. - severity `warn`: Biome is not a CI gate here (only local `code:fix`), and there's a small existing backlog (~17 in src) — this is a ratchet to keep NEW erasures visible, not a hard block. Warnings don't change `biome check`'s exit code (verified). - test/integration/*.test-d.ts files are exempt via an `overrides` entry — test doubles legitimately force-cast; suppress a deliberate src case with `// biome-ignore lint/plugin: <reason>`. - Known limitation (documented in the plugin): matches only the bare forms, not compound casts like `as never[]`. Claude-Session: https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w
|
📝 WalkthroughWalkthroughBiome now enables a local GritQL lint rule that warns on ChangesType-erasing assertion linting
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
biome-plugins/no-type-erasing-assertions.grit (1)
16-26: 🎯 Functional Correctness | 🔵 Trivial | 💤 Low valueHighlight the full assertion span (
biome-plugins/no-type-erasing-assertions.grit:21-24)
Bind the full cast expression inspaninstead of$eso the warning underline matches theas any/as never/as unknowntext.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@biome-plugins/no-type-erasing-assertions.grit` around lines 16 - 26, Update the diagnostic span in the assertion patterns within register_diagnostic to bind the full cast expression, including the as any, as never, or as unknown suffix, instead of only $e. Keep the existing patterns and warning message unchanged so the underline covers the complete type-erasing assertion.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@biome-plugins/no-type-erasing-assertions.grit`:
- Around line 16-26: Update the diagnostic span in the assertion patterns within
register_diagnostic to bind the full cast expression, including the as any, as
never, or as unknown suffix, instead of only $e. Keep the existing patterns and
warning message unchanged so the underline covers the complete type-erasing
assertion.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 1f9486c1-86cc-438c-8a36-999f1215aa0f
📒 Files selected for processing (3)
AGENTS.mdbiome-plugins/no-type-erasing-assertions.gritbiome.json
…obal+exempt The original wiring (top-level `plugins` + an `overrides` entry with `plugins: []` for tests) did NOT exempt tests: Biome runs top-level plugins on every file and `overrides[].plugins: []` does not disable them — verified 158 test-file hits leaking through. Enable the plugin only via an `overrides` entry whose `includes` matches source and negates the test globs instead. Now: 82 source hits, 0 test-path leaks (verified). Also ignore `**/*.grit` in files.includes so Biome stops trying to format the plugin file itself. Claude-Session: https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w
…rated files Level 1 of making Biome a CI gate (errors only; warnings allowed): - Add a `code:check` script (`biome check`, read-only) and run it in tests.yml. `biome check` exits non-zero on ERRORS and zero on warnings, so this gates format/lint/organizeImports errors while the `no-type-erasing-assertions` plugin (and the ~500 pre-existing warnings) stay visible but non-blocking. - Ignore checked-in GENERATED artifacts in biome (prisma-next `contract.*` / `end-contract.*` / `*.generated.ts`, and migration `*.json` / `refs`) — they carry `DO NOT EDIT` and would re-drift on regeneration, so CI must not gate on their formatting. This dropped the error count 36 → 15. - `biome check --write` the 15 remaining errors in AUTHORED files (format + organizeImports only — no logic changes). `biome check` now exits 0. Tightening the gate to fail on warnings (level 3) is tracked as a follow-up. Claude-Session: https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w
Level 1 gate added (per discussion)
Tightening the gate to fail on warnings (burn down the ~521-warning backlog) is tracked in #625 (assigned, before next release). |
Was a step inside the matrixed "Run Tests" job (ran per Node leg, no distinct check line). Split into a standalone `lint` job — no DB/credentials, single Node, so it surfaces as its own "Lint (Biome)" check and runs once. Still gates on errors only (warnings allowed); #625 tracks tightening. Claude-Session: https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w
The dedicated lint job hardcoded Node 24, which trips the supply-chain gate (e2e/tests/supply-chain.e2e.test.ts) requiring every pnpm-using job to pin Node 22 (literal or a matrix including 22). Lint is runtime-agnostic, so pin 22. Claude-Session: https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w
…into chore/biome-no-type-erasing-assertions # Conflicts: # packages/stack/__tests__/v3-matrix/catalog.ts # packages/stack/src/eql/v3/types.ts
What
A Biome GritQL lint plugin (
biome-plugins/no-type-erasing-assertions.grit) that warns on type-erasing assertions in source:x as any,x as never,x as unknown(the last also catches the inner half ofx as unknown as T).These silence the type checker instead of narrowing a value, so a real type mismatch can hide behind them. Came out of the #621 review, where
as nevercasts kept appearing.What it does NOT flag (deliberately)
x as const— a widening-freeze, not an erasure.x as SpecificType— a normal, checked assertion.param: never—neveras a type annotation (e.g. a contravariant parameter) is a legitimate technique, not erasure.Design decisions
warn, noterror. Biome isn't a CI gate in this repo (the only invocation is the localpnpm code:fix), and there's a small existing backlog — 17 occurrences insrcacross all packages. This is a ratchet to keep new erasures visible in the editor andcode:fixoutput, not a hard block. Verified that plugin warnings don't changebiome check's exit code, socode:fixis unaffected.**/__tests__/**,**/*.test.ts,**/*.test-d.ts,**/integration/**,**/tests/**,**/*.spec.tsare exempted via anoverridesentry — test doubles legitimately force-cast. A deliberatesrccase takes a// biome-ignore lint/plugin: <reason>suppression.as never[]/as any[]. Easy to extend later if wanted.To make it a hard gate later
Add a CI step running
biome check(orbiome lint --error-on-warnings), and/or flip severity toerrorafter burning down the 17srcoccurrences. Both are follow-ups, not part of this prototype.Verification
as const/as Foo/neverannotations /as never[]alone.biome checkexit code unchanged by the plugin.https://claude.ai/code/session_01MxTTPaPP16m6br7Hoab94w
Summary by CodeRabbit
as any,as never, andas unknown.