Skip to content

ADR-0019: Pin TypeScript 6 to keep type-aware linting

ADR-0019: Pin TypeScript 6 to keep type-aware linting

  • Status: Accepted
  • Date: 2026-07-30
  • Supersedes:
  • Superseded by:

Context

Scaffolding the monorepo (WI-002) required choosing a TypeScript version, and the obvious answer turned out to be blocked.

Verified against the npm registry on 30 July 2026:

PackageVersionConstraint
typescript7.0.2 latest, 6.0.3 latest 6.x
typescript-eslint8.65.0 latest, 8.65.1-alpha.17 canarytypescript: ">=4.8.4 <6.1.0"

Both the latest and the canary tag of typescript-eslint exclude TypeScript 7. TypeScript 7 is the Go-based compiler rewrite, and the surrounding tooling ecosystem has not caught up.

So the fork is: latest compiler, or type-aware linting. Not both.

Decision

Pin TypeScript 6.0.3 across the monorepo, through packages/config and a single root devDependency.

Rationale

The type-aware typescript-eslint rules are the ones that catch real defects rather than style nits — no-floating-promises, no-misused-promises, no-unsafe-argument. This project is asynchronous Workers code throughout, where an unawaited promise is a silent failure rather than a lint annoyance. Trading those rules for compile speed is the wrong call on a codebase that agents will be writing at volume.

The ecosystem risk points the same way. typescript-eslint excluding TS 7 even on its canary tag is a signal rather than an oversight: Drizzle, Astro, Hono and Expo are all far more likely to be tested against 6.x today. Debugging another project’s TS 7 incompatibility is not work this project should be doing.

Compile speed matters least of the three. Turborepo caching means a warm typecheck is a cache hit, not a compile.

Consequences

  • One minor version behind latest, and slower cold compiles than TS 7 would give.
  • tsconfig.base.json cannot use TypeScript 7-only options.
  • This is a temporary pin, not a permanent position. Revisit it as soon as typescript-eslint ships TS 7 support — the trigger is that package’s peer range, not a calendar date.
  • Every package inherits the version through packages/config, so upgrading is a one-line change plus a gate run rather than a sweep.
  • CI pins the same version, so a local/CI TypeScript mismatch cannot appear silently.

Alternatives considered

TypeScript 7.0.2 with non-type-aware ESLint. Latest compiler, meaningfully faster. Rejected: it trades away the lint rules that catch async bugs, on a codebase that is almost entirely async, and adds unquantified risk across four other stack components.

TypeScript 7.0.2, deferring the lint decision. Keeps momentum. Rejected: it leaves the gate weaker than docs/standards/ci-and-gates.md describes for an unbounded period, and deferring is how a temporary gap becomes permanent.