A Dependabot pull request moved TypeScript from 6.0.3 to 7.0.2. That looks like a routine major-version upgrade. But in an Astro project, it can leave astro check unable to run.

While examining a public Astro/Starlight issue, I found two competing fixes. One proposal removed astro check so that CI would stop calling the failing tool. The other returned TypeScript to version 6, kept the checker, and temporarily stopped Dependabot from proposing 7.x again. The second approach was merged.

This is more than a peer-dependency version-range dispute. TypeScript 7.0 is a native compiler with different integration boundaries; some language tooling still relies on the older programmatic TypeScript APIs. Microsoft’s official TypeScript 7.0 announcement explicitly advised embedded-language ecosystems, including Astro, Vue, Svelte and MDX, to remain on TypeScript 6 while their tooling catches up.

A note on evidence before getting into the fix: I inspected the pinned source files, both pull requests, and the project’s GitHub Actions run. I also executed five dependency-free synthetic Node.js tests demonstrating how package exports can mislead an installation check. I did not run npm install or astro check on the actual project. The successful CI below is the original project’s evidence, not an independent Astro reproduction.

Two repairs: remove the checker, or restore a supported dependency

The incident appears in vishwakarma Issue #8. An earlier Dependabot PR #3 upgraded TypeScript to 7.0.2. The maintainer reported that astro check no longer worked with this combination.

PR #9 suggested cutting the checker out of the workflow. Its patch removed the check script and @astrojs/check package, then dropped typecheck-web from the Makefile so check-web would be reduced to formatting and building. That pull request was closed without being merged.

You can get a green build by ceasing to run a red check, but that is not the same as fixing type checking. astro build does not stand in for the diagnostics astro check provides for .astro templates and TypeScript. Removing the check quietly removes an existing quality gate.

The merged PR #10 kept that gate and instead restored the web workspace dependency:

- "typescript": "^7.0.2"
+ "typescript": "^6.0.3"

In the fixed public commit, apps/web/package.json declares Astro ^7.2.10 and @astrojs/check ^0.9.10. The pinned package-lock.json identifies @astrojs/[email protected] and its peer requirement:

"peerDependencies": {
  "typescript": "^5.0.0 || ^6.0.0"
}

That is a declaration read from the lockfile, not output from an npm command I ran. For this specific checker version, TypeScript 7 is outside the declared supported peer range.

The merged fix also has observable third-party CI evidence. GitHub Actions run #38103905437 ran on PR head 5d828e8d55c5db833f5cca17f28da3b6aba05a99. Its Web job, including make setup-web and make check-web, and its Python job finished successfully. That supports the post-fix state with the checker retained. It does not mean I independently reproduced the failed TypeScript 7 side of the comparison.

How can an installed TypeScript package appear to be missing?

There are two separate compatibility layers.

The deeper one is the compiler API. TypeScript 7.0 moved its compiler to a native implementation. The tsc executable may work, but that alone does not supply the stable programmatic API surface that TypeScript 6 integrations used. Tools such as Astro need to analyze TypeScript inside .astro files and wire it into language services. A newer command-line compiler does not make those integrations compatible by itself.

The more misleading layer is package resolution. Astro’s upstream Issue #17268 documented how TypeScript 7’s package exports could make older detection logic using require.resolve('typescript') throw ERR_PACKAGE_PATH_NOT_EXPORTED. A tool that catches every resolution error and turns it into “TypeScript is not installed” can send developers down the wrong path.

I wanted to verify that narrower mechanism without installing Astro or the real TypeScript 7 package. With Node.js v22.16.0’s standard library, I created two disposable mock packages: one with an ordinary legacy entry point, and another exporting only its ./package.json subpath, not the package root. Here is the relevant configuration from the generated mock, formatted for readability:

{
  name: 'native-ts-synthetic',
  version: '7.0.0-fixture',
  type: 'module',
  exports: {
    './package.json': './package.json'
  }
}

For that synthetic package, require.resolve('native-ts-synthetic') throws ERR_PACKAGE_PATH_NOT_EXPORTED even though the package files exist. Because the mock deliberately exports ./package.json, that subpath resolves and reveals the installed package. A genuinely missing mock returns MODULE_NOT_FOUND for both paths.

I ran node --test ./node-exports-resolution.test.cjs in an isolated Linux environment using Node.js v22.16.0, with no third-party npm packages. A short extract from the real Node TAP output, not an Astro error log:

# OBSERVED: legacy package resolution = FOUND
# OBSERVED: package exists; require.resolve(root) = ERR_PACKAGE_PATH_NOT_EXPORTED
# OBSERVED: require.resolve(package.json) = FOUND
# OBSERVED: absent package = MODULE_NOT_FOUND in both paths
# OBSERVED: catch-all = false missing; code-aware fallback = detected installed
# tests 5
# pass 5
# fail 0

Those five passing tests establish a particular Node.js package-resolution behavior. They do not test TypeScript 7, Astro, or an actual astro check invocation. The package.json fallback is not universal either: packages that do not export that subpath can reject it too.

Even a correct installed-package check cannot magically restore a missing TypeScript 7 programmatic API. Astro’s PR #18053, merged in September 2026, improved the message shown for TypeScript 7; closing the related issue does not itself establish complete 7.0 compatibility.

Restoring CI in an affected Astro project

For an affected version combination, start by checking the installed TypeScript version, the @astrojs/check version, the lockfile’s peer range, and the actual checker error. Do not treat an automatic update recommendation as proof that the whole tooling stack has already migrated.

The example repository has an npm workspace named web under apps/web. These commands are steps a reader can run on their own repair branch, adapted from the actual PR #10. I did not execute them against this project:

# Inspect the dependency versions
npm ls typescript @astrojs/check -w web

# Restore the version used by this particular fix
npm install --save-dev 'typescript@^6.0.3' -w web

# Reinstall exactly from the lockfile and retain both checks
npm ci
npm run check -w web
npm run build -w web

A dependency conflict may make npm ls exit nonzero; that can be useful diagnostic evidence. Preserve the original commit or work on a new branch, check the project’s actual Node/npm requirements, and verify its workspace name before running the commands. For a single-package repo, omit -w web. The ^6.0.3 range is what this pinned case used, not a permanent recommendation for every Astro project.

Then prevent the same automatic major update from repeatedly reopening the issue. The project’s pinned .github/dependabot.yml contains this npm-scoped temporary rule:

- package-ecosystem: npm
  directory: /
  schedule:
    interval: weekly
  ignore:
    - dependency-name: typescript
      versions: [">=7.0.0"]

Put the rule under the npm configuration, not under a blanket ignore of unrelated dependencies. Write down when you intend to revisit it: after Astro’s relevant checker and language tooling support the newer integration path, and after your own CI actually passes. Otherwise a temporary workaround can quietly become an indefinite version freeze.

In this example, check-web includes formatting, astro check and the build. A meaningful fix verification should check that the lockfile pins the intended combination, npm ci can reproduce the install, astro check actually runs, and the build still finishes. If the project already has a known .astro type-error fixture, verifying that the checker still catches it is stronger than relying solely on a green aggregate badge.

Does TypeScript 7.1 mean the pin can be removed?

A temporary downgrade need not become the long-term architecture. Microsoft’s original TypeScript 7.0 guidance discussed the continuing programmatic API work and options such as @typescript/typescript6 that let older tools coexist with the newer tsc. But compiler command-line support, Astro template analysis, editor language services, and CI checking are distinct adoption tests.

At the time of this research, Astro #17268 was closed, the clearer error guidance from PR #18053 was merged, while the Content Mapper work for .astro and TypeScript 7 in PR #17852 was still open. These are time-specific source observations, not a guarantee of what later Astro or TypeScript 7.1 releases support.

For someone whose astro check just failed after a TypeScript major upgrade, the practical sequence is to inspect the error and dependency contract, retain the checker, restore a supported combination, verify the lockfile and CI, and schedule a separate migration assessment later. The goal is to recover real checking—not merely to stop a red CI job from making noise.

For background on why I chose this stack in the first place, see my earlier Astro, Markdown and GitHub Actions comparison. Here the question is what happens after choosing Astro, when the next automated dependency update threatens one of the safeguards the project already had.