# Astro check が TypeScript 7 で失敗したら：型チェックを消さずに依存関係を直す

> Canonical: https://vxi.me/ja/posts/astro-check-typescript-7-compatibility/
> Locale: ja-jp
> Published: 2026-10-11
> Updated: 2026-10-11
> Markdown: https://vxi.me/ja/posts/astro-check-typescript-7-compatibility.md

Dependabot の PR が TypeScript を 6.0.3 から 7.0.2 に上げた。バージョン番号だけ見れば普通のメジャーアップデートだ。しかし Astro プロジェクトでは、それをきっかけに `astro check` が動かなくなることがある。

[Astro / Starlight を使う公開プロジェクトの Issue](https://github.com/sivadotblog/vishwakarma/issues/8)を調べていて、二つの対処案が目に留まった。一つは `astro check` 自体を CI から外す方法。もう一つは TypeScript を 6 に戻し、チェックは残したまま、Dependabot による 7.x への自動更新をいったん止める方法だ。**実際にマージされたのは後者だった。**

問題は単なる peer dependency の宣言違反だけではない。TypeScript 7.0 はネイティブコンパイラへの移行で、従来の TypeScript API を内部で使う言語ツールがまだ追いついていない。[Microsoft の TypeScript 7.0 リリース記事](https://devblogs.microsoft.com/typescript/announcing-typescript-7-0/)も、Astro、Vue、Svelte、MDX のような埋め込み言語ツールについては、移行が整うまで TypeScript 6 を使うよう案内している。

証拠の範囲は先に明確にしておく。固定コミットの依存関係、二つの修正 PR、元のプロジェクトの GitHub Actions を確認した。さらに Node.js の標準機能だけで 5 件の合成テストを実行し、`exports` によって「インストール済みなのに見つからない」と誤判定される仕組みを確かめた。**元の Astro プロジェクトに対する `npm install` や `astro check` は実行していない。** 後述する CI 成功は元のプロジェクトによる第三者の実行結果だ。

## チェックを削除するか、対応するバージョンに戻すか

発端は [vishwakarma Issue #8](https://github.com/sivadotblog/vishwakarma/issues/8) に記録されている。[Dependabot PR #3](https://github.com/sivadotblog/vishwakarma/pull/3) で TypeScript を 7.0.2 に更新した後、メンテナーが `astro check` の互換性問題を報告した。

[PR #9](https://github.com/sivadotblog/vishwakarma/pull/9) は、チェックそのものを外す案だった。`apps/web/package.json` の `check` スクリプトと `@astrojs/check` を削除し、Makefile から `typecheck-web` を取り除く。残る `check-web` はフォーマットチェックとビルドだけになる。この PR はクローズされ、**マージされていない**。

チェックを実行しなければ CI が緑色に戻ることはある。ただし、`astro build` の成功は、`astro check` が担っていた `.astro` テンプレートや TypeScript の型診断が成功したことを意味しない。失敗したチェックを隠すために、元々あった品質ゲートを捨てるのは別の問題を作ってしまう。

マージされた [PR #10](https://github.com/sivadotblog/vishwakarma/pull/10) は、チェッカーを残して Web workspace の依存バージョンを元に戻した。

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

修正後の[固定コミット](https://github.com/sivadotblog/vishwakarma/tree/9837d456647d948207941c86244e253594aef9ae)を読むと、`apps/web/package.json` には Astro `^7.2.10`、`@astrojs/check` `^0.9.10` が記載されている。そして同じコミットの [`package-lock.json`](https://github.com/sivadotblog/vishwakarma/blob/9837d456647d948207941c86244e253594aef9ae/package-lock.json) では、`@astrojs/check@0.9.10` が対応する TypeScript の peer 範囲を次のように宣言している。

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

これは**ロックファイルの記述を確認した結果**であり、私が npm を実行して出したエラーログではない。少なくとも、このバージョンのチェッカーは TypeScript 7 をサポート範囲に含めていない。

修復後の状態には第三者の CI 証拠もある。[GitHub Actions #38103905437](https://github.com/sivadotblog/vishwakarma/actions/runs/38103905437) は PR head `5d828e8d55c5db833f5cca17f28da3b6aba05a99` で実行され、Web job の `make setup-web` と `make check-web`、Python job が成功した。これは**チェックを保持した修復後**についての証拠であり、TypeScript 7 側の失敗を私が独立再現したという意味ではない。

## TypeScript が入っているのに「見つからない」と出る理由

互換性の問題は少なくとも二層ある。

深い層はコンパイラ API だ。[TypeScript 7.0](https://devblogs.microsoft.com/typescript/announcing-typescript-7-0/) は Go によるネイティブ実装へ移行した。`tsc` コマンドが動いても、TypeScript 6 の安定したプログラマティック API まで提供されるわけではない。Astro は `.astro` ファイルの中に埋め込まれた TypeScript を、独自の言語サービスを通じて解析する。コンパイラの実行ファイルだけを更新しても、その連携が自動的に直るわけではない。

もう一層は、問題の見せ方を紛らわしくする。Astro 上流の [Issue #17268](https://github.com/withastro/astro/issues/17268) には、TypeScript 7 のパッケージ `exports` の変更により、古い検出コードの `require.resolve('typescript')` が `ERR_PACKAGE_PATH_NOT_EXPORTED` を返す場合があると記録されている。解析エラーをすべて「TypeScript が未インストール」と解釈すれば、ユーザーは見当違いの対応を試してしまう。

この Node.js 側の仕組みだけは自分でも確認しておきたかった。そこで Astro と実物の TypeScript 7 は入れず、Node.js v22.16.0 の標準ライブラリで使い捨てのモックパッケージを二つ生成した。一つは従来型の入口があり、もう一つは `./package.json` のみ公開し、パッケージのルートを公開しない。後者で実際に使った設定の主要部分は次のとおりだ。

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

この**合成モック**に `require.resolve('native-ts-synthetic')` を実行すると、ファイルが存在していても `ERR_PACKAGE_PATH_NOT_EXPORTED` になる。一方、明示的に公開した `native-ts-synthetic/package.json` は解決できる。そもそも存在しないパッケージなら、いずれも `MODULE_NOT_FOUND` になる。

隔離された Linux 環境の Node.js v22.16.0 で、第三者 npm パッケージを使わず `node --test ./node-exports-resolution.test.cjs` を実行した。以下は**実際の Node TAP ログ**からの抜粋であり、Astro の実行ログではない。

```text
# 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
```

5 件すべてが成功したことで分かったのは、**Node.js の特定のパッケージ解決の挙動**だけだ。実際の TypeScript 7、Astro、`astro check` を検証したわけではない。また、`package.json` を代わりに参照する方法はどのパッケージにも使えるものではなく、そのサブパスを公開していなければ同じように失敗する。

さらに、インストール判定の誤表示を修正しても、TypeScript 7.0 にない旧 API が生まれるわけではない。Astro の [PR #18053](https://github.com/withastro/astro/pull/18053) は 2026 年 9 月にマージされ、TypeScript 7 向けのエラー説明を改善した。関連 Issue のクローズだけをもって、7.0 との完全な互換性が実現したと結論づけることはできない。

## 影響を受けた Astro プロジェクトの CI を戻すには

まず実際の TypeScript と `@astrojs/check` のバージョン、ロックファイルの peer 範囲、表示されているエラーを調べる。Dependabot がアップグレードを提案したからといって、フレームワークの言語ツールまで対応済みとは限らない。

この公開リポジトリでは npm workspace の名前が `web`、ディレクトリが `apps/web` だ。以下は [PR #10](https://github.com/sivadotblog/vishwakarma/pull/10) の修正内容を踏まえた、**読者が自分の修復ブランチで試すための手順**。私は元のプロジェクトでこれらを実行していない。

```bash
# まず使用中の依存関係を確認
npm ls typescript @astrojs/check -w web

# このケースで使われた互換バージョンへ戻す
npm install --save-dev 'typescript@^6.0.3' -w web

# ロックファイルから再インストールし、チェックとビルドを確認
npm ci
npm run check -w web
npm run build -w web
```

依存関係が壊れている場合、`npm ls` 自体が非ゼロで終了することもあり、それが診断材料になる。元のコミットを保存するか、別の修復ブランチで行い、Node/npm の要求バージョンと実際の workspace 名を確かめてほしい。単一パッケージなら `-w web` は不要だ。`^6.0.3` は**この固定した事例の選択**であり、全 Astro プロジェクトに対する永久的な推奨値ではない。

もう一つ必要なのは、同じ自動更新 PR を繰り返さないことだ。固定コミットの [`.github/dependabot.yml`](https://github.com/sivadotblog/vishwakarma/blob/9837d456647d948207941c86244e253594aef9ae/.github/dependabot.yml) には、npm の更新項目に次のルールがある。

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

これは **npm 用**の一時的な制限として設定する。関係のない依存まで更新停止にしないようにしたい。解除条件も忘れずに書いておく。Astro のチェッカーや言語サービスが新しい方式に対応し、**自分の CI** で確認できた時点でルールを見直す。仮の回避策を永遠の固定バージョンにしないためだ。

この事例の `check-web` は整形チェック、`astro check`、ビルドを含んでいる。修復の検証では、ロックファイルが正しい組み合わせを示すか、`npm ci` で再現性のあるインストールができるか、`astro check` が本当に実行されるか、ビルドも通るかをそれぞれ見る。`.astro` の型エラーを検出する既存のフィクスチャがあれば、その検出機能が失われていないか確認するとさらに確実だ。

## TypeScript 7.1 があれば、すぐに 6 の固定を外せるのか

一時的に旧バージョンへ戻すことは、永続的に移行を諦めることではない。Microsoft は TypeScript 7.0 の発表で新しいプログラマティック API の開発と、`@typescript/typescript6` のように旧ツールと新しい `tsc` を共存させる方法に触れている。ただし、`tsc` の実行、Astro テンプレートの解析、エディタ言語サービス、CI の型チェックは別々に動作確認する必要がある。

調査時点では、Astro [#17268](https://github.com/withastro/astro/issues/17268) はクローズされ、説明を改善する [PR #18053](https://github.com/withastro/astro/pull/18053) はマージ済み。一方、`.astro` を TypeScript 7 の Content Mapper へ渡す [PR #17852](https://github.com/withastro/astro/pull/17852) はオープンだった。これはその時点の記録であり、後の Astro／TypeScript リリースの状態まで保証するものではない。

TypeScript のメジャー更新で `astro check` が壊れたら、まずエラーと依存関係の契約を確認し、**型チェックを残したまま**対応する組み合わせへ戻し、ロックファイルと CI を再検証する。その後、新しい方式への移行を別件として計画すればよい。目標は単に赤い CI を消すことではなく、元々あった検査を機能させ続けることだ。

Astro を選んだ理由については、以前書いた [Astro、Markdown、GitHub Actions の比較](https://aitokenhacks.com/posts/astro-vs-wordpress-markdown-github-actions-blog/)にまとめている。今回の話は、その選択をした後の自動依存更新が、知らないうちに既存の品質チェックを削ってしまわないようにするための話だ。
