Skip to content

Non-deterministic TS2430 on merged global Window — count and reported sites vary across identical vue-tsc runs (plain tsgo is stable) #42

Description

@Togetic

Summary

Running vue-tsc on TNB over an unchanged program produces a different set of TS2430 diagnostics
on each run
— different counts, and attributed to a varying subset of the interface Window
augmentation sites. No file changes, no config changes between runs.

The same program checked with plain tsgo (@typescript/native-preview, no bridge) is
deterministic across the same number of runs, which is what points here rather than at
microsoft/typescript-go.

Observed

Project: Nuxt 4 / Vue 3 monorepo, ~2,700 first-party .ts + .vue files. moduleResolution: "Bundler",
strict: true.

TNB — vue-tsc via nuxt typecheck, TNB 6.0.3-bridge.6.tsgo.7.0.2. Three consecutive runs, no
changes between them:

Run TS2430 count Sites reported
1 2 declarations/global.ts:71, recaptcha/recaptchaLoader.ts:10
2 1 recaptcha/recaptchaLoader.ts:10
3 2 composables/payment/useRiskSession.ts:6, recaptcha/recaptchaLoader.ts:10

An earlier 3-run set on the same branch (before an unrelated first-party fix) varied 6 / 4 / 4, with the
same pattern: one site always present, the others appearing and disappearing.

Plain tsgo — tsgo -p tsconfig.tsgo.json --noEmit, @typescript/native-preview@7.0.0-dev.20260707.2,
same repo, same commit.
Three consecutive runs:

Run TS2430 count Sites reported
1 2 declarations/global.ts, recaptcha/recaptchaLoader.ts
2 2 declarations/global.ts, recaptcha/recaptchaLoader.ts
3 2 declarations/global.ts, recaptcha/recaptchaLoader.ts

Stable, and note the site set also differs from TNB's: plain tsgo never reports useRiskSession.ts,
while TNB sometimes does.

The message is error TS2430: Interface 'Window' incorrectly extends interface 'GoogleTagManagerApi'.
The program has several declare global { interface Window … } augmentations — some first-party (one
with its own extends clause), plus third-party ones from @nuxt/scripts shaped as
declare global { interface Window extends GoogleTagManagerApi {} }. Stock tsc@5.9.3 reports no
TS2430 at all on this program.

Why this looks bridge/Volar-side rather than tsgo-side

  • Plain tsgo on the same commit is deterministic (above).
  • The two paths do not even agree on which sites are implicated.
  • The obvious type-level suspect is disproven: a standalone repro of @nuxt/scripts'
    dataLayer: DataLayer & { push: DataLayerPush } (Array.push returns number, DataLayerPush
    returns void) plus multiple Window augmentations, one with its own extends clause, is clean on
    both tsc and tsgo. So the intersection alone is not the trigger and I could not minimise the real
    one.

Caveat I want to be explicit about: the two configurations differ in two ways, not one — bridge vs
native-preview, and vue-tsc/Volar over the full solution (including .vue) vs plain tsgo over a
.ts-only project. So this could be a Volar file-ordering interaction surfaced through the bridge
rather than the bridge itself. I could not separate those two variables, because stock tsc reports
zero TS2430 on this program and so gives no baseline to compare counts against.

Expected

For a fixed program, the diagnostic set is deterministic run to run.

Environment

  • TNB 6.0.3-bridge.6.tsgo.7.0.2 (installed via pnpm-workspace.yaml overrides plus an explicit
    "typescript": "npm:typescript-native-bridge@…" devDependency — the override alone was not enough
    here, as nothing in the workspace declares typescript and TNB's prerelease version does not satisfy
    the typescript: ">=5.0.0" peer ranges that vue-tsc / @typescript-eslint declare)
  • vue-tsc 3.3.5, Nuxt 4.4.8, macOS arm64, Node 24.18
  • @typescript/native-preview@7.0.0-dev.20260707.2 for the plain-tsgo comparison

Happy to run instrumented builds or try to narrow the Volar-vs-bridge split with guidance on what
would be useful.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions