Skip to content

Commit 15b246b

Browse files
committed
chore(lint): warn on type-erasing assertions via a Biome GritQL plugin
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
1 parent e9e81e6 commit 15b246b

3 files changed

Lines changed: 47 additions & 1 deletion

File tree

AGENTS.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,12 @@ Three rules to remember when editing CI or pnpm config:
177177
pnpm run code:fix
178178
```
179179

180+
A Biome GritQL plugin (`biome-plugins/no-type-erasing-assertions.grit`) warns
181+
on `as any` / `as never` / `as unknown` in `src` — type-erasing assertions that
182+
silence the checker instead of narrowing. Fix the type or use a specific
183+
assertion; suppress a deliberate case with `// biome-ignore lint/plugin:
184+
<reason>`. Test/integration files are exempt (see `overrides` in `biome.json`).
185+
180186
- **Build**: `pnpm run build` (Turborepo + tsup per package)
181187
- **Test**: `pnpm --filter <pkg> test` for targeted iterations
182188
- **Releases**: Use Changesets
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Flags type-erasing assertions: `x as any`, `x as never`, `x as unknown`
2+
// (the last also catches the inner half of `x as unknown as T` double-casts).
3+
//
4+
// These punch a hole through the type system rather than narrowing a value, so
5+
// a real type mismatch can hide behind them (e.g. passing the wrong shape to a
6+
// function whose signature you've silenced). Prefer fixing the underlying type,
7+
// narrowing with a guard, or a precise `as SpecificType`.
8+
//
9+
// NOT flagged: `as const` (a widening-freeze, not an erasure), a plain
10+
// `as SpecificType`, or `never` used as a *type annotation* (e.g. a contravariant
11+
// `param: never`) — those are legitimate.
12+
//
13+
// Warning, not error: the repo has a large existing backlog, and this is a
14+
// ratchet to keep NEW erasures visible. Intentional cases take a
15+
// `// biome-ignore lint/plugin: <reason>` suppression.
16+
or {
17+
`$e as any`,
18+
`$e as never`,
19+
`$e as unknown`
20+
} where {
21+
register_diagnostic(
22+
span = $e,
23+
message = "Avoid type-erasing assertions (`as any` / `as never` / `as unknown`) — they silence the checker instead of narrowing. Fix the underlying type, use a type guard, or assert a specific type. Suppress an intentional case with `// biome-ignore lint/plugin: <reason>`.",
24+
severity = "warn"
25+
)
26+
}

biome.json

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,19 @@
3030
"noThenProperty": "off"
3131
}
3232
}
33-
}
33+
},
34+
"plugins": ["./biome-plugins/no-type-erasing-assertions.grit"],
35+
"overrides": [
36+
{
37+
"includes": [
38+
"**/__tests__/**",
39+
"**/*.test.ts",
40+
"**/*.test-d.ts",
41+
"**/integration/**",
42+
"**/tests/**",
43+
"**/*.spec.ts"
44+
],
45+
"plugins": []
46+
}
47+
]
3448
}

0 commit comments

Comments
 (0)