71 lines
2.6 KiB
Markdown
71 lines
2.6 KiB
Markdown
|
|
# ADR 0004: TypeScript 6.0.3 rather than 7.x
|
||
|
|
|
||
|
|
- **Status:** accepted
|
||
|
|
- **Date:** 2026-10-04
|
||
|
|
- **Revisit when:** typescript-eslint ships TypeScript 7 support
|
||
|
|
|
||
|
|
## Context
|
||
|
|
|
||
|
|
The brief was to take the latest version of everything. For TypeScript, the latest
|
||
|
|
release is 7.0.2, which is the native Go port of the compiler (`tsgo`).
|
||
|
|
|
||
|
|
## Decision
|
||
|
|
|
||
|
|
Pin TypeScript to 6.0.3 in both `web/` and `sdk/`.
|
||
|
|
|
||
|
|
## Rationale
|
||
|
|
|
||
|
|
TypeScript 7.0.2 ships `tsc.js` and a version module. It does **not** ship a
|
||
|
|
JavaScript compiler API:
|
||
|
|
|
||
|
|
```console
|
||
|
|
$ npm install typescript@7.0.2
|
||
|
|
$ node -e "const ts=require('typescript'); console.log(typeof ts.createProgram)"
|
||
|
|
undefined
|
||
|
|
```
|
||
|
|
|
||
|
|
That API is what every type-aware linting tool consumes. `typescript-eslint@8.71.0`,
|
||
|
|
the current release, declares:
|
||
|
|
|
||
|
|
```
|
||
|
|
peerDependencies: { typescript: ">=4.8.4 <6.1.0" }
|
||
|
|
```
|
||
|
|
|
||
|
|
So TypeScript 7 fails to install at all alongside the standard linting stack, and
|
||
|
|
would fail at run time if forced past the peer check.
|
||
|
|
|
||
|
|
The choice is therefore between:
|
||
|
|
|
||
|
|
- **TypeScript 7.x** — a much faster compiler, and no type-aware ESLint rules at all,
|
||
|
|
because the tooling that provides them cannot run. `npm install` fails outright
|
||
|
|
without `--legacy-peer-deps`, which is a smell in a project rather than a solution.
|
||
|
|
- **TypeScript 6.0.3** — the newest release that ships both the CLI and the
|
||
|
|
JavaScript API, satisfying every tool in the toolchain.
|
||
|
|
|
||
|
|
## Why not upgrade anyway and lose the linting
|
||
|
|
|
||
|
|
The project's standards require type-aware linting: `@typescript-eslint` rules that
|
||
|
|
need the compiler's type information, which is what catches the mistakes that matter
|
||
|
|
in a codebase using `unknown` at API boundaries. Dropping it to gain compiler speed
|
||
|
|
is a bad trade: the speed is a developer-experience improvement, and the linting is
|
||
|
|
a correctness control.
|
||
|
|
|
||
|
|
## What this costs
|
||
|
|
|
||
|
|
TypeScript 6.0.3 is slower than 7.0.2. On this codebase the typecheck completes in
|
||
|
|
well under a second, so the difference is not observable, and the compilation cost
|
||
|
|
that matters is Vite's, which uses its own transform.
|
||
|
|
|
||
|
|
## When to revisit
|
||
|
|
|
||
|
|
When typescript-eslint declares support for TypeScript 7, which requires the
|
||
|
|
JavaScript API or a native alternative to it. That is a one-line version bump plus
|
||
|
|
a `make check` run. This ADR exists so that the pin is a decision with a reason
|
||
|
|
rather than an accident that outlives its justification.
|
||
|
|
|
||
|
|
## A related note: `baseUrl` is deprecated
|
||
|
|
|
||
|
|
TypeScript 6 deprecates `compilerOptions.baseUrl`. The project resolves `paths`
|
||
|
|
relative to the tsconfig instead, which is the documented replacement and removes a
|
||
|
|
compiler option that only ever existed to make `paths` work.
|