0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

tsconfig.json 型エラーとmoduleResolution

0
Posted at

背景

Chakra UI v3 でダイアログ(モーダル)を実装したところ、TypeScript から次のエラーが出た

型 '{ children: Element; }' には型 'DialogPositionerProps' と共通のプロパティがありません。

このエラーメッセージはそのまま読んでも何が問題なのか分かりにくい
原因をたどると tsconfig.jsonmoduleResolution の設定値が原因ぽかった

結論

解決策は moduleResolution"node" から "bundler" に変更すること

以下、エラーの正体・原因・moduleResolution の役割を順に整理する

内容

1. このエラーは「タイプミスを疑っている」エラー

TypeScript のエラーコードでいう TS2559 に該当する。発動条件は次の1点

渡そうとしている props と、受け取り側の型に、共通するキーが1個もない

通常 TypeScript は「足りない」「余計だ」と指摘してくる。一方 TS2559 は「キーが1つも噛み合っていない」状態専用で、「これはタイプミスかコピペミスではないか?」と TypeScript が強めに警告している状態を示す

2. 今回はタイプミスではなく、ライブラリの型情報が壊れていた

JSX で次のように書いたとする。

<Dialog.Positioner>
  <Dialog.Content>...</Dialog.Content>
</Dialog.Positioner>

TypeScript は内部でこう変換している。

Dialog.Positioner({
  children: <Dialog.Content>...</Dialog.Content>
})

つまり「children というキーを1つだけ持つオブジェクト」を渡している状態。本来 Dialog.Positionerchildren を受け取れる型として定義されているはずだが、今回は型情報が壊れて children を受け取れない型になっていた

そのため「渡している側のキー: children のみ」「受け取り側が知っているキー: children を含まない別のもの」となり、共通キーがゼロ → TS2559 が発動するという流れ

3. なぜ型が壊れたか — moduleResolution の話

tsconfig.json とは

TypeScript に「このプロジェクトをどう扱ってほしいか」を伝える設定ファイル。代表的な項目は次のとおり。

項目 意味
target どの JavaScript バージョンに変換するか
strict 型チェックの厳しさ
include 対象とするフォルダ・ファイル
moduleResolution ← 今回の要因。モジュール(ライブラリ)の探し方

moduleResolution とは

import { x } from 'y' と書いたとき、TypeScript は 'y' という名前だけを頼りに「どのファイルが本体なのか」を解決する必要がある。その解決ルールを決めるのが moduleResolution

主な値の比較

想定環境 特徴
"node" 古い Node.js 古いルール。最近のライブラリの最新機能を読めない
"node16" / "nodenext" 新しい Node.js 新ルール対応。バックエンド向け
"bundler" Vite / Webpack / Next.js などのフロント向けビルドツール 最新ルール対応 + 柔軟。フロント開発の標準
"classic" TypeScript 初期の独自方式 ほぼ使われない(非推奨)

決定的な差: 「サブパス」を解決できるかどうか

最近のライブラリは package.jsonexports フィールドで「入口を細かく分ける」設定を書いている

// 例: あるライブラリの package.json
{
  "exports": {
    ".":        "./dist/index.js",     // メイン入口
    "./dialog": "./dist/dialog.js"     // サブ入口(subpath)
  }
}

これによって「メインの入口」と「個別パーツ用の入口」を分けて公開できる。

  • "node" → この exports を読めない
  • "bundler" → 読める

これが今回の原因

4. 今回起きたことの整理

Chakra UI の Dialog の型は、内部で別のライブラリ(Ark UI)の型をサブパス経由で参照している

// Chakra の内部(イメージ)
import { Dialog as ArkDialog } from "@ark-ui/react/dialog"
//                                  ^^^^^^^^^^^^^^^^^^^^^^
//                                  ↑ サブパス経由で型を参照

プロジェクトの tsconfig.jsonmoduleResolution"node" のままになっていた → Ark UI のサブパス型が解決できない → Chakra の型チェーンが途中で切れる → 本来含まれるはずの children が型から消える → TS2559(共通プロパティなし)が出る、という感じ

5. 補足: 関連するエラーコードと設定値

TS2559 と類似エラーの違い

エラーコード メッセージ 発動条件
TS2559 共通のプロパティがありません キーが1個も噛み合わない特殊ケース
TS2322 型 X を型 Y に割り当てれない 一般的な型不一致
TS2353 既知のプロパティしか指定できない 余計なプロパティがある
TS2741 プロパティ X が不足している 必須のプロパティがない

TS2559 だけが「キーが1個も噛み合わないとき専用」という独特の性格を持つ。

moduleResolution 設定値の早見表

// tsconfig.json
{
  "compilerOptions": {
    "moduleResolution": "bundler"  // フロントエンド標準
    // または "nodenext"          // 最新 Node.js
    // または "node16"            // 特定の Node.js バージョン
    // または "node"              // ← レガシー、使わない
  }
}

まとめ

  • tsconfig.jsonmoduleResolution"Node""bundler" に変更することで解決した

     {
       "compilerOptions": {
    -    "moduleResolution": "Node",
    +    "moduleResolution": "bundler",
       }
     }
    
  • 環境別の選び方の指針

    環境 選ぶ値
    Vite / Next.js / Webpack(フロントエンド) "bundler"
    最新の Node.js(バックエンド) "nodenext"
    Node.js のバージョンを固定したい "node16"
    古い CommonJS 環境(やむを得ず) "node"
  • 最近のライブラリ(Chakra v3、Ark UI、Radix、TanStack 系など)を使うなら "node" は実質使ってはいけない値

感想

  • そもそもTS慣れてないと、型系のエラー内容がイマイチ読めない

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?