ReviewOS

stacks/dtsx

Proposal: test-per-TS-code coverage — scope to 34 declaration-emit (TS9xxx) codes, not 2k

#3098
Open glennmichael123 opened this 9 days ago ·
9 days ago

Background

Chris floated the idea: "would it make sense in dtsx to have one test against every single ts code?" — there are ~2076 upstream TypeScript diagnostic codes, so the literal reading is a 2,000-test addition.

This issue is a sizing pass on that idea before any code gets written. TL;DR: the axis is good, the count is ~25× too big.

What dtsx already covers

packages/dtsx/test/ already has 30 test files plus 26/22 input/output fixtures, organized by feature group, not by error code:

  • Feature: ts-features.test.ts, generics, class, interface, type, enum, namespace, module, imports, exports, async-generators, branded-types, directives, type-mappings, isolated-declarations
  • Output safety: snapshots, output-normalizer, dts, formatter, errors
  • Perf / infra: parallel-processor, cache, memory, profiling, fuzzing
  • Regression: issue-3093, issue-3095

Coverage by topic is solid. A test-per-TS-code suite is a different axis — exhaustive by error-code identifier rather than by feature group.

The TS code universe

Source: home-lang/home@docs/TS_DIAGNOSTIC_CODE_STATUS.md — Home maintains the canonical generated catalogue (2,076 codes).

Code rangeCountRelevance to dtsx
TS9xxx — isolated-declarations / declaration-emit34Directly relevant. These are the exact failure modes a .d.ts generator has to handle: TS9007 "Function must have explicit return type", TS9013 "Expression type can't be inferred", TS9021 "Extends clause can't contain expression", etc. dtsx's pitch — "infers narrow types from source values without requiring isolatedDeclarations" — is literally solving these.
TS1xxx — parser errors~90Partially relevant. Most are about malformed user source; dtsx doesn't emit them. The useful subset is ~10–15: codes dtsx could accidentally emit in output (TS1005 } expected, TS1009 trailing commas, TS1010 */ expected — same family as the Promise<; breakage stacks' scripts/patch-broken-dts.ts papers over).
TS2xxx, TS22xx–TS25xx — type-checker semantic~370Not relevant. Type-CHECKING failures, not GENERATION concerns. dtsx is upstream of these.
TS17xx, TS18xx — modules / JSDoc~67Mostly not relevant beyond a handful of re-export codes.

Proposal — three tiers, ~50 tests total

Tier 1 — 34 tests, one per TS9xxx code (highest leverage)

For each TS9xxx code, write a minimal fixture input that would trigger that error under tsc --isolatedDeclarations. Assert:

  1. dtsx generates a .d.ts without crashing.
  2. The output parses cleanly (no TS1xxx syntax errors).
  3. Re-running tsc --noEmit over the output does not re-trigger the original TS9xxx code.

Example skeleton for TS9007 (function must have explicit return type):

// input.ts — would error TS9007 under --isolatedDeclarations
export function makeUser(name: string) {
  return { name, createdAt: Date.now() }
}

// Assertion against dtsx output:
//   1. produces a .d.ts containing `export function makeUser(name: string): { name: string; createdAt: number; }`
//   2. tsc --noEmit on the .d.ts is clean
//   3. tsc --isolatedDeclarations does not flag TS9007

Tier 2 — ~15 output-safety tests (parser-code subset)

Regression tests for parser codes dtsx could emit: TS1005, TS1009, TS1010, TS1011, TS1013, TS1014, TS1015, plus a few more. Tier 2 catches "dtsx wrote syntactically invalid declarations" bugs — exactly the class that scripts/patch-broken-dts.ts had to hand-patch in stacks for bun-query-builder and ts-images.

Tier 3 — optional gap-fill (~0–50 tests)

By TS feature spec, not by error code: mapped types, conditional types, template-literal types, infer, satisfies, decorators, etc. Most of this is already covered by existing files (type-mappings.test.ts, branded-types.test.ts, etc.); Tier 3 is "fill the gaps we don't have yet", not "rewrite from scratch".

Mechanics, if Tier 1 ships

  • The TS9xxx list is machine-readable in home-lang/home@docs/TS_DIAGNOSTIC_CODE_STATUS.md with each code's canonical key (e.g. Function_must_have_an_explicit_return_type_annotation_with_isolatedDeclarations_9007).
  • Small generator script → one stub file per code (tier1-ts9007.test.ts, …), each pre-populated with the canonical key in the description.
  • Hand-craft the fixture input per file.
  • Re-use existing test infra (test-utils.ts, the input/output fixture loader, processCode).

Decision points for review

  1. Scope — Tier 1 only (34 tests, ~1 day) vs Tier 1 + Tier 2 (~50 tests, ~2 days). Tier 3 happens organically as feature gaps are noticed.
  2. Assertion strictness — byte-exact .d.ts snapshots vs targeted toContain checks vs round-trip-through-tsc-only.
  3. Skip vs include the catalog-only TS9xxx codes — TS9005, TS9006, TS9026 are catalog-only (Home doesn't reference them yet). Still relevant for dtsx? Probably yes — but worth flagging.

Not starting on this until someone signs off on the scope.

cc: @chrisbreuer

Sign in to comment on this issue.