Status: Proposed (recommendation: Adopt as opt-inDocumentation Index
Fetch the complete documentation index at: https://docs.encoreos.io/llms.txt
Use this file to discover all available pages before exploring further.
tsgo-powered fast path now; promote to default when stable ships and the typescript-eslint peer range opens for TS 7.x)
Date: 2026-04-23
Owners: Platform Architecture
Related: ADR-009 Biome formatter, .github/workflows/build.yml, CI_PIPELINE.md
Context
On 2026-04-21 Microsoft published TypeScript 7.0 Beta. TS 7.0 is a Go port of the existing TypeScript codebase (“Project Corsa”), shipping under the@typescript/native-preview package and the tsgo entry point. Microsoft positions it as semantically equivalent to TS 6.0 with stableTypeOrdering on and ignoreDeprecations unset; the headline value is ~10× faster type-checking via native code and shared-memory parallelism.
This ADR records a structured evaluation against the Encore Health OS codebase and recommends a phased adoption.
Repo baseline (as of this ADR)
| Item | Value |
|---|---|
Declared TS in package.json | typescript@^6.0.3 |
| Resolved TS in lockfile | 6.0.3 (registry tarball) |
Currently installed in node_modules | 5.9.3 (peer-dep deduplication via npm ci --legacy-peer-deps) |
| Configs | tsconfig.json (root) → references tsconfig.app.json and tsconfig.node.json. App config: target: ES2020, module: ESNext, moduleResolution: bundler, noEmit, strict: false + strictNullChecks: true, incremental cache at node_modules/.cache/tsc/app.tsbuildinfo. |
| Typecheck script | tsc --noEmit -p tsconfig.app.json --incremental --tsBuildInfoFile node_modules/.cache/tsc/app.tsbuildinfo (single-config invocation; no tsc --build). |
| CI typecheck | npm run typecheck in .github/workflows/build.yml, with node_modules/.cache/tsc cached across runs. Cold run is the slow path; warm runs hit the incremental cache. |
| TS Compiler API consumers | 3 audit scripts: scripts/audit/doc-comment-coverage/parser.ts, scripts/audit/audit-appicon-tones.ts, scripts/audit/audit-page-spacing.ts (all import ts from 'typescript'). |
| Linter | typescript-eslint@^8.59.0 (currently installed: 8.58.2). Peer range published in installed packages: typescript >=4.8.4 <6.1.0. |
Other TS-API consumers in node_modules: | ts-node@10.9.2, msw@2.13.2, @vitest/*@4.1.5, vite-plugin-checker@0.13.0, eslint-plugin-tsdoc@0.5.2. (Fallow is a Rust binary and not a TS Compiler API consumer.) |
ignoreDeprecations | Not set in any tsconfig. |
What TS 7.0 actually changes for us
- Same compiler semantics as TS 6.0 (per Microsoft’s stability statement and 10-year test suite re-run).
- New binary name:
tsgo. Thetypescriptpackage will re-take thetscentry point only when 7.0 goes stable. - A compatibility shim (
@typescript/typescript6exposingtsc6) lets you keep TS 6.x available for tools that importtypescriptas a peer. stableTypeOrderingbecomes the assumed default; anyignoreDeprecationsusage breaks (we use neither, so this is a non-issue here).- No stable programmatic API in 7.0 yet — Microsoft explicitly defers that. Tools that import the TS Compiler API must keep using TS 6.x for now.
Evaluation: empirical results on this repo
We installed@typescript/native-preview@beta (tsgo v7.0.0-dev.20260421.2) alongside the existing TS 6.0.3 toolchain and compared against tsc --noEmit -p tsconfig.app.json on the same source tree, same tsconfig, same machine. Cache was cleared before each “cold” run.
| Run | Compiler | Wall time | Errors |
|---|---|---|---|
| Cold typecheck | tsc (TS 6.0.3) | 7m 58s (478s) | 0 |
| Cold typecheck | tsgo (TS 7.0 beta) | 0m 53s (53s) | 0 |
| Warm typecheck (incremental cache hit) | tsc (TS 6.0.3) | 7m 53s (no incremental cache benefit on this run; see note) | 0 |
| Warm typecheck (no incremental cache; tsgo doesn’t need one) | tsgo (TS 7.0 beta) | 3.6s | 0 |
Note on warmDiagnostics parity: zero errors emitted in either compiler for this commit. No new errors, no removed errors, no different ones. Key implication for CI: CI typecheck cold time (when thetsc: the secondtscrun was effectively another cold compile because the.tsbuildinfowas generated against atscfrom the freshly installed npm tree (TS 6.0.3) and the cache was not preserved across thetsgoinstall in our test environment. In CI, the warm-cache path normally completes in ~8s as documented in the build workflow, which roughly matchestsgo’s warm-run number — so the truly meaningful comparison is cold ~478s → cold ~53s (~9× faster) and warm ~8s (cached) → warm ~3.6s (no cache needed) (~2× faster, with simpler cache semantics).
tsc-${{ runner.os }}-… cache key misses, which happens any time tsconfig*.json, package-lock.json, or src/integrations/supabase/types.ts changes — i.e., on most dependency bumps and on every Supabase types regeneration) drops from ~8 minutes to ~1 minute. Warm runs are already fast and stay fast. The Supabase types.ts regeneration is currently the single biggest CI typecheck cliff, and tsgo flattens it.
Constraints and risks
typescript-eslintpeer range still excludes TS ≥ 6.1.0. Installed versions in our tree advertisetypescript >=4.8.4 <6.1.0. v8.58.0 added TS 6 support; TS 7 official support is expected in a future major. Until that ships, the linter must continue to resolvetypescriptto a 6.x build. Thenpm:@typescript/typescript6alias is the supported workaround.- No stable programmatic API in TS 7.0. Our three audit scripts (
audit-appicon-tones.ts,audit-page-spacing.ts,doc-comment-coverage/parser.ts)import ... from 'typescript'. They must keep resolving against TS 6.x. The compatibility package handles this transparently. ts-nodepeer range:node_modules/ts-node@10.9.2advertisestypescript: >=2.7so it accepts both. We usets-nodefor ~15 utility scripts; keep it pointed at the sametypescriptresolution as the linter (TS 6.x via alias).- MSW, Vitest, Vite,
vite-plugin-checker,eslint-plugin-tsdoc: all consume the TypeScript package or its compiler API. None of them have published explicit TS 7 peer ranges yet. They will keep resolving against the aliased TS 6.xtypescriptentry — this is exactly what the Microsoft compatibility recipe is for. tsc --build(project references): Ourtsconfig.jsonlists references but ourtypecheckscript invokestsc -p tsconfig.app.jsondirectly, so build-mode caching is not in play.tsgoaccepts-p. No script changes are needed beyond replacing the binary name.incrementalandtsBuildInfoFileflags:tsgodoes not need--incrementalto be fast (warm 3.6s without one). The flags are harmless to leave in for the TS 6 fallback path;tsgoignores or accepts them.- Beta lifecycle: Microsoft plans GA “within the next two months” (i.e. on the order of June 2026), with a release candidate a few weeks before. Behavior is described as “finalized” only at RC. Until then there is non-zero risk of compatibility-affecting fixes between dev releases.
- No Encore-specific blocker found. We don’t use
ignoreDeprecations. We don’t use removed legacy compiler options. We don’t ship a TS-emit pipeline (noEmit: true). Vite +@vitejs/plugin-reactdoes the actual JS transform; TS is type-check only here. This makes us an unusually safe candidate for early adoption. - CI cache key. The existing build workflow keys on
tsconfig*.json/package-lock.json/src/integrations/supabase/types.ts. If we keep bothtscandtsgoon the same tsconfig, no key change is required. If we add a separatenode_modules/.cache/tsgopath, it should be added to the cache step.
Options Considered
Option A: Stay on TS 6.0.x for the foreseeable future (status quo)
- Pros: Zero migration work, maximal tooling compatibility, deterministic.
- Cons: Cold typecheck remains ~8 min and is the dominant cost in CI when cache misses; developer feedback on dependency bumps and Supabase types regeneration is poor; we leave a ~9× perf win on the table on a 4,000+-file codebase that already has incremental cache as its only mitigation.
Option B: Adopt @typescript/native-preview now as an opt-in npm run typecheck:fast/tsgo script, keep tsc (TS 6.x) as the source of truth for CI gates and editor parity, no peer-dep changes ✓ (recommended Phase 1)
- Pros: Zero risk to existing CI gate. Developers immediately get sub-minute cold typechecks locally. Editor experience can switch to the TypeScript Native Preview VS Code extension per developer choice. Audit scripts, linter, ts-node, and build all continue resolving the existing TS 6.x install. Empirically validated on this repo (cold 478s → 53s, no diagnostic changes).
- Cons: CI still pays the cold-cache cost on Supabase types regeneration until we cut over the gate.
Option C: Cut CI typecheck over to tsgo immediately, install typescript as alias npm:@typescript/typescript6 so linter/audit scripts/ts-node still see TS 6.x
- Pros: Captures the ~9× cold-CI win immediately.
- Cons: TS 7.0 is still beta;
npm install -D typescript@npm:@typescript/typescript6plus a separate@typescript/native-previewinstall is a non-trivial lockfile change; warm CI is already ~8s, so the absolute CI minutes saved per run are modest unless the cold-cache path (Supabase types regen, dep bumps, branch creation) is what’s hurting. Defer to Phase 2.
Option D: Wait for TS 7.0 GA and then migrate
- Pros: Maximum stability; benefit from RC-period fixes; ride along with
typescript-eslint’s native TS 7 support when it lands. - Cons: ~2-month delay on developer-experience wins; no learning prior to GA; no validation against our specific audit scripts and Supabase-types regeneration cliff.
Decision (recommendation)
Adopt Option B now. Plan Option C as Phase 2 once two conditions are met: (a) TS 7.0 reaches RC or GA, (b)typescript-eslint publishes a release whose peer range includes TS 7.x. Track Phase 2 as a follow-up issue, not a blocker.
Concretely:
Phase 1 (now — recommended action)
- Add
@typescript/native-previewas adevDependency(pinned to a known beta version, e.g.^7.0.0-dev.20260421.2, with renovate updates allowed). - Add a new npm script:
Leave the existing
typecheckscript (TS 6 +tsc) unchanged as the gate. - Add a brief note to AGENTS.md “Pre-Flight Checklist → Before commit” pointing developers at
npm run typecheck:fastfor local iteration. Keepnpm run validate(which runs the slowtscpath) as the authoritative gate. - Document the optional VS Code “TypeScript Native Preview” extension in
docs/development/DEVELOPMENT_QUICK_REFERENCE.mdas a developer-choice ergonomic upgrade. - Do not modify the linter, audit scripts,
ts-node,tsBuildInfoFile, or the CI cache key. Do not aliastypescript. Do not change peer-dep ranges.
Phase 2 (when TS 7.0 hits RC/GA AND typescript-eslint ships TS 7-compatible peer range)
- Replace the root
typescriptdependency with the alias:"typescript": "npm:@typescript/typescript6@^6.0.0"(keeps the API for linter, audit scripts, MSW, Vitest, ts-node, and vite-plugin-checker). - Add the stable
typescript@^7.xdependency separately, exposingtsc(the TS 7 entry point). - Switch
npm run typecheckand CI’s “Typecheck” step to use the newtsc(TS 7). - Drop the
--incremental/--tsBuildInfoFileflags from the typecheck script (no longer needed for performance), and removenode_modules/.cache/tscfrom the cache step. Optionally add a smallernode_modules/.cache/tsgocache entry if measurement shows it helps. - Update AGENTS.md §“Pre-Flight Checklist → Before commit”, CI_PIPELINE.md, and the typecheck section of .github/workflows/build.yml comments.
- Run
npm run validateand the full unit/integration/RLS smoke baseline before merging.
Phase 3 (post-Phase-2 cleanup)
- Once
typescript-eslint,ts-node,msw,vitest,vite-plugin-checker, andeslint-plugin-tsdocall advertise TS 7-compatible peer ranges, drop the@typescript/typescript6alias and the audit-script keep-alive comments; lettypescriptresolve to 7.x natively.
Consequences
Positive
- Sub-minute cold typecheck for developers immediately (Phase 1) — biggest single ergonomic win on this repo since incremental cache.
- Zero behavior delta in our codebase (validated: identical zero-error result on this commit).
- ~7-minute cold-CI win once Phase 2 lands (every Supabase types regeneration, dep bump, or PR with a tsconfig change saves ~7 minutes of CI wall time).
tsgoremoves the need to babysit--incremental/tsBuildInfoFilecache invalidation.
Negative / Risks
- Two compilers coexist locally during Phase 1 (small node_modules footprint cost; one extra binary).
- Phase 2 timing depends on third-party (
typescript-eslint) release cadence. - Beta dev-stream releases of
tsgochange frequently; we should pin and let renovate roll. - Until Phase 2,
npm run typecheckcontinues to be the ~8-minute cold path in CI.
Mitigations
- Phase 1 is intentionally additive: nothing existing changes.
- The cutover (Phase 2) is gated on RC/GA + linter compatibility, so we don’t ship a beta into the CI gate.
- All TS Compiler API consumers (3 audit scripts plus 6 third-party tools) are explicitly enumerated above; the
@typescript/typescript6alias keeps every one of them working. ignoreDeprecationsis not in use anywhere, removing the most common 6→7 break.
Empirical evidence (commands and results)
Reproducible on a fresh clone of this commit on a Linux x64 dev box:Related Documents
- Implementation plan: TYPESCRIPT_7_MIGRATION_PLAN.md — concrete diffs, gating criteria, verification commands, and rollback procedures for Phases 1–3.
- Microsoft announcement: https://devblogs.microsoft.com/typescript/announcing-typescript-7-0-beta/
- TS 6→7 transition +
@typescript/typescript6compatibility package (linked from the announcement) - .github/workflows/build.yml — CI typecheck cache configuration
- package.json —
typecheck,validate,buildscripts - tsconfig.app.json — primary type-check config
- ADR-009 Biome formatter — precedent for adopting native-code dev-ergonomics tooling