Skip to content

chore: make tsc --noEmit clean again — and fix the one real bug it was hiding#561

Merged
kaihaase merged 1 commit into
developfrom
chore/typecheck-clean
Jul 15, 2026
Merged

chore: make tsc --noEmit clean again — and fix the one real bug it was hiding#561
kaihaase merged 1 commit into
developfrom
chore/typecheck-clean

Conversation

@kaihaase

Copy link
Copy Markdown
Member

Problem

tsc --noEmit -p tsconfig.json reported 8 errors on develop. Nothing in the check chain runs it — nest build uses tsconfig.build.json, which already excludes the two problem files — so the errors only ever surfaced as red squiggles in the editor. They were ignored long enough that a genuine bug hid among them.

The real bug

vite.config.ts sets tsCompiler: 'esbuild', but vite-plugin-node@8 narrowed SupportedTSCompiler to 'vite' | 'swc':

// node_modules/vite-plugin-node/dist/index.d.ts:17
export declare type SupportedTSCompiler = 'vite' | 'swc';

The config would not work if anyone ran it. Switched to 'swc', which the project already uses elsewhere (nest start -b swc).

The rest — fixed at the root, not silenced

File Error Fix
scripts/generate-framework-api.ts import.meta cannot typecheck under module: commonjs (TS1343) The package is CommonJS (no "type": "module"), so tsx runs the script as CJS and __dirname is native — the fileURLToPath(import.meta.url) shim was never needed. Removed.
vite.config.ts, migration-project.template.ts vite@8 is ESM-only and unresolvable under moduleResolution: node (which module: commonjs forces); the template deliberately imports @lenne.tech/nest-server because it is copied into consumer projects Excluded from the root tsconfig, mirroring tsconfig.build.json
tests/unit/performance-caches.spec.ts:732 override against a base class whose compile-time type is any (it comes from a dynamic import) — TS rejects this outright (TS4113) Dropped the modifier; the method still overrides at runtime
tests/unit/unified-field-whitelist.spec.ts ×3 email redeclared without an initializer (TS2612) Added = undefined, matching every Input class in the codebase

Note on the approach: a separate ESM tsconfig.json for scripts/ is not an option — scripts/init-server.ts imports src/, which would drag the whole import x = require(...) tree into ESM mode (26× TS1202). Fixing the shim at the source is the only clean route.

Verification

  • tsc --noEmit0 errors (was 8)
  • npx tsx scripts/generate-framework-api.ts still runs and regenerates the file
  • Full pnpm run check green: audit, format, lint, tests, build, server-start

Why separate from #559

Pure hygiene, unrelated to the 401/403 work. Reviewable and revertable on its own.

🤖 Generated with Claude Code

… was hiding

`tsc --noEmit -p tsconfig.json` reported 8 errors on develop. Nothing in the check chain runs it
(`nest build` uses tsconfig.build.json, which already excludes the two problem files), so the errors
only surfaced as red squiggles in the editor -- and were ignored long enough that a genuine bug hid
among them.

The real bug: vite.config.ts sets `tsCompiler: 'esbuild'`, but vite-plugin-node@8 narrowed
SupportedTSCompiler to 'vite' | 'swc'. The config would not work if anyone ran it. Switched to
'swc', which the project already uses elsewhere (`nest start -b swc`).

The rest were configuration mismatches, each fixed at the root rather than silenced:

- scripts/generate-framework-api.ts shimmed __dirname from `import.meta.url`, which cannot typecheck
  under `module: commonjs`. The package IS CommonJS (no "type": "module"), so tsx runs the script as
  CJS and __dirname is native -- the shim was never needed. Removed. (A separate ESM tsconfig for
  scripts/ is not an option: scripts/init-server.ts imports src/, which would drag the whole
  `import x = require(...)` tree into ESM mode.)
- vite.config.ts and the migrate template are excluded from the root tsconfig, mirroring
  tsconfig.build.json. vite@8 is ESM-only and cannot be resolved under `moduleResolution: node`,
  which `module: commonjs` forces; the template deliberately imports '@lenne.tech/nest-server' because
  it is copied into consumer projects.
- performance-caches.spec.ts marked a method `override` against a base class whose compile-time type
  is `any` (it comes from a dynamic import), which TS rejects outright (TS4113).
- unified-field-whitelist.spec.ts redeclared `email` without an initializer (TS2612). Added
  `= undefined`, matching every Input class in the codebase.

Verification: `tsc --noEmit` now reports 0 errors; the generator still runs; full check green.
@kaihaase
kaihaase force-pushed the chore/typecheck-clean branch from b37eedc to a1628db Compare July 15, 2026 08:42
kaihaase added a commit that referenced this pull request Jul 15, 2026
….28.0 review

Two unrelated bits of housekeeping that were sitting in the working tree.

**.gitignore** — `.lt-dev/` is created per worktree by the `lt dev` CLI and has no business being
tracked.

**.claude/agent-memory/** — written by the review agents during the 11.28.0 (401/403) review. These
are the findings worth carrying forward, not the review prose:

- `security-reviewer/project-exception-wire-format.md` — `HttpExceptionLogFilter` serializes
  `{ ...exception }` for REST, so a custom `HttpException` subclass silently changes the wire body
  (`name`, `options`) AND breaks `instanceof` against the native Nest exceptions. This is the finding
  that would otherwise have shipped a silent breaking change in #559.
- `backend-reviewer/project_401-403-denial-surface.md` — the framework has five permission-denial
  layers, and they used to contradict each other. A change to one is a change to none.
- `docs-reviewer/release-version-artifacts.md` — `spectaql.yml` carries the version too and is
  derived from `package.json`, but only by `pnpm run docs`, never by `build`. It is therefore
  reliably forgotten in release commits.
- `test-reviewer/e2e-isolation-model.md` — e2e files share ONE database per run and execute in
  parallel forks, so any unscoped write to global state (a `jwks` wipe, a config mutation) strands
  the other files. Pair-run to reproduce; an isolated re-run proves nothing.

Kept separate from #559 and #561 on purpose: neither is part of a code change.
kaihaase added a commit that referenced this pull request Jul 15, 2026
….28.0 review (#562)

Two unrelated bits of housekeeping that were sitting in the working tree.

**.gitignore** — `.lt-dev/` is created per worktree by the `lt dev` CLI and has no business being
tracked.

**.claude/agent-memory/** — written by the review agents during the 11.28.0 (401/403) review. These
are the findings worth carrying forward, not the review prose:

- `security-reviewer/project-exception-wire-format.md` — `HttpExceptionLogFilter` serializes
  `{ ...exception }` for REST, so a custom `HttpException` subclass silently changes the wire body
  (`name`, `options`) AND breaks `instanceof` against the native Nest exceptions. This is the finding
  that would otherwise have shipped a silent breaking change in #559.
- `backend-reviewer/project_401-403-denial-surface.md` — the framework has five permission-denial
  layers, and they used to contradict each other. A change to one is a change to none.
- `docs-reviewer/release-version-artifacts.md` — `spectaql.yml` carries the version too and is
  derived from `package.json`, but only by `pnpm run docs`, never by `build`. It is therefore
  reliably forgotten in release commits.
- `test-reviewer/e2e-isolation-model.md` — e2e files share ONE database per run and execute in
  parallel forks, so any unscoped write to global state (a `jwks` wipe, a config mutation) strands
  the other files. Pair-run to reproduce; an isolated re-run proves nothing.

Kept separate from #559 and #561 on purpose: neither is part of a code change.
@kaihaase
kaihaase merged commit e319dfc into develop Jul 15, 2026
1 check passed
@kaihaase
kaihaase deleted the chore/typecheck-clean branch July 15, 2026 08:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant