Skip to content

Client: Upgrade TypeScript to 6.0/7.0 dual-compiler setup to match VxSuite along with additional related cleanup - #2373

Open
nikhilb4a wants to merge 7 commits into
mainfrom
client-typescript-7
Open

Client: Upgrade TypeScript to 6.0/7.0 dual-compiler setup to match VxSuite along with additional related cleanup#2373
nikhilb4a wants to merge 7 commits into
mainfrom
client-typescript-7

Conversation

@nikhilb4a

@nikhilb4a nikhilb4a commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Closes #1471

Commits

  1. Upgrade TypeScript to the 6.0/7.0 dual-compiler setup, with the native 7.0 compiler as tsc.
  2. Switch tsc to noEmit type-checking, since we don't use the emitted files.
  3. Fix the VS Code workspace TypeScript SDK path.
  4. Mark client Makefile targets .PHONY.
  5. Add client lint and production-build steps to CI to catch build issues before deploy.
  6. Replace the create-react-app-era react-app-env.d.ts types with vite-env.d.ts since we've moved to vite.
  7. Drop @types/jspdf and @types/react-toastify, unused since those packages now ship their own types.

Update Typescript 6.0/7.0 dual-compiler setup

Upgraded to match the same Typescript setup used on VxSuite. Dual-TS version setup is standard for apps using tools like eslint, cypress, since TS7 doesn't have full API support required for those. That is expected to come in TS7.1 in late 2026/early 2027.

Install typescript 7.0.2 (native compiler) for the tsc binary and @typescript/typescript6 6.0.2 as the typescript package for tools that consume the JS API (typescript-eslint, tsserver, Cypress).

  • moduleResolution "node" was removed in TS 7; switch to "bundler"
  • resolvePackageJsonExports: false defers a react-hook-form v7 upgrade (v6's exports map hides its type declarations from bundler resolution)
  • vite-env.d.ts satisfies TS 7's new check that side-effect CSS imports resolve (TS2882)

Why

  • ~15x faster type-checking. A full tsc run on the client drops from ~30s to under 2s
    (measured on this repo). That speed shows up everywhere tsc runs:
    • every commit — the pre-commit hook type-checks via lint-staged
    • CI — test:ci runs tsc before vitest
    • local development
  • Stays on the supported TypeScript line. 5.9 closed out the JS-only era of the compiler;
    new language features, lib updates, and bug fixes now ship in the 6.x/7.x lines. This keeps
    us current without waiting until an upgrade is forced by a dependency.
  • Matches VxSuite's setup. Same dual-package scheme
    (typescript@typescript/typescript6, @typescript/nativetypescript@7), so both
    VotingWorks codebases follow one convention: the fast native compiler on the tsc binary,
    the behavior-matched JS compiler on the typescript package for API consumers.
  • Zero tooling churn. typescript-eslint, tsserver, Vite/Vitest, and Cypress keep consuming
    the TypeScript JS API through the typescript alias — lint output is byte-identical before
    and after (0 errors, 19 warnings), and the test suite is unaffected. The bigger
    ESLint/typescript-eslint upgrade stays a separate, independent project.
  • Better editor experience available. With TS 7 installed, the
    TypeScript Native Preview
    VS Code extension can run the editor language service on the native compiler too (optional;
    the default tsserver keeps working via the TS 6 package).

Install typescript 7.0.2 (native compiler) for the tsc binary and
@typescript/typescript6 6.0.2 as the typescript package for tools
that consume the JS API (typescript-eslint, tsserver, Cypress).

- moduleResolution "node" was removed in TS 7; switch to "bundler"
- resolvePackageJsonExports: false defers a react-hook-form v7 upgrade
  (v6's exports map hides its type declarations from bundler resolution)
- vite-env.d.ts satisfies TS 7's new check that side-effect CSS imports
  resolve (TS2882)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@nikhilb4a
nikhilb4a force-pushed the client-typescript-7 branch from 79b5b8f to eb111c1 Compare August 17, 2026 18:04
nikhilb4a and others added 2 commits August 17, 2026 22:26
The declaration/emitDeclarationOnly/outDir setup wrote a dist/ tree of
.d.ts files on every tsc run (CI and pre-commit) that nothing consumes:
the app is bundled by Vite into build/, and no tooling reads client/dist.
noEmit expresses the actual intent — tsc is a type-check gate only.

rootDir must still be set explicitly (with a comment saying why):
Cypress loads cypress.config.ts through ts-node, which forces an
internal outDir, and TS 6 fails there with error TS5011 when rootDir
is left inferred. This is also what broke the Cypress CI job after
the TS 6/7 upgrade.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The typescript package is now the @typescript/typescript6 wrapper,
which ships no lib/tsserver.js, so VS Code silently fell back to its
bundled TypeScript. Point tsdk at @typescript/old (the real TS 6
compiler the wrapper re-exports), which does ship tsserver.js.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@nikhilb4a
nikhilb4a force-pushed the client-typescript-7 branch from d3a6197 to 2d51e74 Compare August 17, 2026 22:27
nikhilb4a and others added 4 commits August 17, 2026 22:47
make build silently no-ops when Vite's build/ output directory exists,
because make treats the directory as the target being up to date.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Client lint previously ran only in the pre-commit hook (skippable, and
absent for bot commits), and vite build ran for the first time at
deploy — a change could pass CI and still fail the Heroku build.
build-and-test-client now runs both, using the existing client
Makefile targets.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
vite/client (referenced by vite-env.d.ts) already declares every asset
module the CRA shim declared. The shim's *.svg ReactComponent export
was a trap: the CRA idiom type-checked but is undefined at runtime
under Vite (no svgr plugin). Its NODE_ENV literal-union narrowing is
the one piece worth keeping, so it moves to vite-env.d.ts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
jspdf 4 and react-toastify 5 ship their own type declarations, which
TypeScript prefers over @types packages, so these v1-era and v4-era
stubs were never consulted — only available to drift from the real
APIs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@nikhilb4a
nikhilb4a force-pushed the client-typescript-7 branch from dbf207d to 059247c Compare August 17, 2026 23:22
@nikhilb4a
nikhilb4a requested a review from kshen0 August 17, 2026 23:32
@nikhilb4a nikhilb4a changed the title Client: Upgrade TypeScript to 6.0/7.0 dual-compiler setup to match VxSuite Client: Upgrade TypeScript to 6.0/7.0 dual-compiler setup to match VxSuite with additional related cleanup Aug 17, 2026
@nikhilb4a nikhilb4a changed the title Client: Upgrade TypeScript to 6.0/7.0 dual-compiler setup to match VxSuite with additional related cleanup Client: Upgrade TypeScript to 6.0/7.0 dual-compiler setup to match VxSuite along with additional related cleanup Aug 17, 2026
@nikhilb4a
nikhilb4a marked this pull request as ready for review August 17, 2026 23:33
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.

Code Quality: Upgrade TypeScript

2 participants