Context
Dependabot PR #3 proposed bumping TypeScript from 5.9.3 to 6.0.3 (alongside @types/node 22→25). The PR was closed because the jumps needed real work rather than a drive-by merge. Dependabot is now pinned to ignore major bumps for both packages (see .github/dependabot.yml) until we do this migration explicitly.
What TypeScript 6 caught
Running npm run typecheck on the v6 branch surfaced two failure classes:
1. Stricter control-flow analysis in src/cli.ts
async function main(): Promise<void> {
let args: ParsedArgs;
try {
args = parseArgs(process.argv);
} catch (err) {
process.stderr.write(...);
process.exit(64);
}
if (args.help) { // ← TS6 now says: "Variable 'args' is used before being assigned."
...
}
}
TS 6 no longer treats process.exit(64) as unconditionally terminating within a catch block for the purpose of definite-assignment analysis. This is a real latent bug: if parseArgs threw and (hypothetically) process.exit was mocked or the catch didn't exit, args would be undefined. Fix options:
- Restructure so
args is assigned in both branches (cleanest).
- Use a non-null assertion (
args!.help) — lazy, loses the check.
- Explicit
return / throw after process.exit to narrow the type.
2. Global process no longer auto-included
error TS2591: Cannot find name 'process'. Do you need to install type definitions for node?
This appears to be related to how @types/node and tsconfig.json's implicit types interact in TS 6. Likely fix: add \"types\": [\"node\"] to the compilerOptions block, or set \"moduleResolution\" appropriately. Needs investigation — may also affect other @types/* discoverability.
Acceptance criteria
Out of scope
- Moving
engines.node above 22. Keep that separate.
- Switching away from
tsc to swc / esbuild / other compilers. Different discussion.
Notes for the next contributor
Good first issue if you're comfortable with TypeScript's strict mode. Likely 20–50 lines of code change plus config. Read `THREAT_MODEL.md` and `WAYS_OF_WORKING.md` (referenced from the README) before starting — the project has a test-first rule and the `args` restructure should include a unit test covering the "parseArgs throws" path.
Context
Dependabot PR #3 proposed bumping TypeScript from 5.9.3 to 6.0.3 (alongside
@types/node22→25). The PR was closed because the jumps needed real work rather than a drive-by merge. Dependabot is now pinned to ignore major bumps for both packages (see.github/dependabot.yml) until we do this migration explicitly.What TypeScript 6 caught
Running
npm run typecheckon the v6 branch surfaced two failure classes:1. Stricter control-flow analysis in
src/cli.tsTS 6 no longer treats
process.exit(64)as unconditionally terminating within acatchblock for the purpose of definite-assignment analysis. This is a real latent bug: ifparseArgsthrew and (hypothetically)process.exitwas mocked or the catch didn't exit,argswould beundefined. Fix options:argsis assigned in both branches (cleanest).args!.help) — lazy, loses the check.return/throwafterprocess.exitto narrow the type.2. Global
processno longer auto-includedThis appears to be related to how
@types/nodeandtsconfig.json's implicit types interact in TS 6. Likely fix: add\"types\": [\"node\"]to thecompilerOptionsblock, or set\"moduleResolution\"appropriately. Needs investigation — may also affect other@types/*discoverability.Acceptance criteria
^6.0.3(or whatever is current at the time of migration)@types/nodebumped to matchengines.node(currently>=22, so^22.xis correct — not 25)src/cli.tsmain()restructured soargsis definitely assigned; no non-null assertions addedtsconfig.jsonupdated to declare\"types\": [\"node\"](or equivalent) so Node globals resolvenpm run checkpasses (typecheck + lint + 102 tests)CHANGELOG.mdentry under UnreleasedDECISIONS.mdentry explaining the migration trigger and any API surface changesOut of scope
engines.nodeabove 22. Keep that separate.tsctoswc/esbuild/ other compilers. Different discussion.Notes for the next contributor
Good first issue if you're comfortable with TypeScript's strict mode. Likely 20–50 lines of code change plus config. Read `THREAT_MODEL.md` and `WAYS_OF_WORKING.md` (referenced from the README) before starting — the project has a test-first rule and the `args` restructure should include a unit test covering the "parseArgs throws" path.