import typeを省いても、型としてしか使わないimportが自動で消える設定はあります。一方、verbatimModuleSyntax: trueでは書き方によって副作用の実行まで変わりました。型検査に通るかと、読み込み先が実行されるかを分けて確認します。
特に注意したいのは、次の2つが常に同じ出力になるわけではない点です。
import type { Ticket } from "./registry.js"import { type Ticket } from "./registry.js"
読み込み先に目印だけを置く
検証環境は2026年9月11日、macOS arm64、Node.js 24.15.0、TypeScript 7.0.2、esbuild 0.28.2です。コンパイラはstrict: true、target: ES2022、module: ESNext、moduleResolution: Bundler。esbuildはNode向けESM、bundle有効、tree shaking有効で実行しました。テストパッケージにsideEffects: falseは付けていません。
registry.tsには型と、評価されたことを示すログだけを置きます。外部アクセスや実アプリの初期化処理はありません。
export interface Ticket { title: string }
console.log("registry evaluated");
呼び出し元の基本形は次のコードです。
import { Ticket } from "./registry.js";
const ticket: Ticket = { title: "Fix timer" };
console.log(ticket.title);
このimportだけを書き換え、生成JavaScriptと実行ログを比較しました。実際の個人リポジトリでも、型共有パッケージはexport typeでAPIの型を公開しています。今回のTicketとログは、型の参照と実行時の読み込みを切り分けるために用意した最小例です。
書き方と設定で結果が分かれた
表の「評価」は、registry evaluatedが出力されたことを指します。どの成功例も、呼び出し元はFix timerを出力しました。
| importの形 | verbatim | tsc | tsc出力でregistry評価 | esbuild bundleでregistry評価 |
|---|---|---|---|---|
import { Ticket } |
false | 成功 | なし | なし |
import type { Ticket } |
false | 成功 | なし | なし |
import { type Ticket } |
false | 成功 | なし | なし |
副作用import + import type
|
false | 成功 | あり | あり |
import { Ticket } |
true | TS1484 | 出力を止めた | あり |
import type { Ticket } |
true | 成功 | なし | なし |
import { type Ticket } |
true | 成功 | あり | あり |
副作用import + import type
|
true | 成功 | あり | あり |
noEmitOnError: trueを指定しているため、TS1484の行ではtscのJavaScriptを実行していません。esbuildはその入力をbundleできましたが、型検査が通ったことにはなりません。
inlineのtypeは空のimportを残した
verbatimModuleSyntax: trueでimport { type Ticket }と書いたケースのtsc出力です。
import {} from "./registry.js";
const ticket = { title: "Fix timer" };
console.log(ticket.title);
Ticketという名前は消えても、import {} from "./registry.js"が残ります。モジュールを評価する依存はあるため、目印のログが出ました。文全体を型専用にしたimport type { Ticket }では、import文ごと消えてログも出ませんでした。verbatimModuleSyntaxの公式説明も、この2つの出力を区別しています。
型だけが必要なら文全体をimport typeにします。初期化も必要な場合は、それを別のimportとして明示できます。
import "./registry.js";
import type { Ticket } from "./registry.js";
const ticket: Ticket = { title: "Fix timer" };
console.log(ticket.title);
この形は今回の両設定と両ツールでログを出しました。ただし、依存パッケージが副作用なしと宣言している場合や、別のbundle設定でも同じになるとは限りません。ここで観測したのはローカルの2ファイルです。
bundleができても型は確かめられていない
export const count: number = "wrong";
console.log(typeof count);
これはtscでTS2322になりましたが、esbuildは成功し、実行結果はstringでした。esbuildのTypeScriptに関する制約でも、型注釈の検査はTypeScriptの型チェッカー側で行うことを説明しています。
型だけの依存を明示することと、型チェックをビルド工程で実行することは別の対策です。今回の再現では、importの削除だけを見れば動く入力でも、tscが検出する誤りをbundle成功だけでは拾えませんでした。
比較入力のT06ケースを実行スクリプトで処理すると、診断・生成JavaScript・ログをまとめて確認できます。アプリへ設定を導入するときも、型専用の参照と初期化目的の読み込みをそれぞれ確認します。