TypeScript 5.9のimport deferは、モジュールの読み込みと評価を分離し初回アクセスまで評価を遅らせる構文です。名前空間インポート限定のルールや動的importとの使い分け、nodenextでのエラーを確認できます。
この記事が解決する悩み
- 起動時に読み込まれるモジュールの評価を遅らせたい
- import deferと動的importの使い分けが分からない
対象読者: TypeScriptでフロントエンドやNodeのコードを書く人
前提知識: ESMのimportを理解していること
結論
TypeScript 5.9のimport deferは、モジュールの読み込みと評価(トップレベル実行)を分離する構文です。静的importが読み込みと同時に評価されるのに対し、こちらはプロパティに初めてアクセスするまで評価を遅らせられます。
// 読み込みは即時、評価は初回アクセス時まで遅延
import defer * as analytics from "./analytics.js";
// この時点ではanalyticsモジュールはまだ評価されていない
console.log("App started");
// 初めてプロパティにアクセスした瞬間に評価される
analytics.track("page_view");
使えるのは名前空間インポート(import defer * as ns)だけで、名前付きimportやdefault importは書けません。
import deferの基本構文とルール
使える構文・使えない構文
制約は名前空間インポート限定の一点に集約されます。
// これだけが正しい
import defer * as feature from "./feature.js";
// 名前付きimportは不可
import defer { doSomething } from "./feature.js";
// default importも不可
import defer feature from "./feature.js";
// 名前空間なしも不可
import defer "./feature.js";
「プロパティアクセス時に評価をトリガーする」仕様なので、ns.valueのようにアクセスする名前空間オブジェクトでないと遅延の契機を取れないんですね。
TypeScriptのコンパイラ設定
import deferを使うにはmoduleオプションをesnextかpreserveに設定します。
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"moduleResolution": "bundler",
"strict": true
}
}
TypeScriptはimport deferをdownlevelしません。そのままランタイムやバンドラに任せる設計で、nodenextなど他の設定ではコンパイルエラーになります。
静的import vs 動的import vs import defer
ES Modulesの3種類のimportを並べると、違いはこうなります。
| 特性 | 静的import | 動的import | import defer |
|---|---|---|---|
| 解決(resolve) | 即時 | 呼び出し時 | 即時 |
| 取得・解析 | 即時 | 呼び出し時 | 即時 |
| 評価(実行) | 即時 | Promise解決時 | 初回プロパティアクセス時 |
| 同期/非同期 | 同期 | 非同期(Promise) | 同期 |
| 返値 | なし(静的宣言) | Promise | ModuleNamespace |
| コード分割 | 不可 | 可能 | 読み込みは事前完了 |
重いモジュールを遅延読み込みするなら動的importが定番でしたが、非同期処理なので使う側もasync/awaitに巻き込まれます。
// 動的importの場合:非同期処理が必要
async function loadSettings() {
const config = await import("./heavy-config.js");
return config.default;
}
// import deferの場合:同期的に書ける
import defer * as config from "./heavy-config.js";
function loadSettings() {
// ここで初めて評価される
return config.default;
}
実践ユースケース
ユースケース1: 起動時間の改善
アプリ起動時に不要なモジュールの評価を遅らせるケースです。
// heavy-analytics.ts
console.log("Analytics module evaluating...");
const start = Date.now();
while (Date.now() - start < 500) {
/* CPUバウンドな処理 */
}
export function track(event: string) {
console.log("Track: " + event);
}
export const APP_VERSION = "1.0.0";
// main.ts
import defer * as analytics from "./heavy-analytics.js";
console.log("App started");
// 起動時間に500msのオーバーヘッドなし
button.addEventListener("click", () => {
analytics.track("button_click");
});
静的importだと起動時にheavy-analyticsが評価されて500msブロックしますが、import deferならユーザーがボタンをクリックするまで評価されません。
ユースケース2: プラットフォーム固有のコード
実行環境で使うモジュールが変わる場合にも効きます。
// storage-web.ts
export function save(key: string, value: string) {
localStorage.setItem(key, value);
}
// storage-node.ts
import { writeFileSync } from "node:fs";
export function save(key: string, value: string) {
writeFileSync("./data/" + key + ".json", value);
}
// main.ts
import defer * as storage from "./storage-web.js";
export function savePreference(key: string, value: string) {
storage.save(key, value);
}
起動時に両方を評価したり、動的importで非同期を強いられたりせず、初回使用時まで評価を遅延できます。
ユースケース3: 巨大な設定ファイルやi18nリソース
// i18n-resources.ts
export const resources = {
ja: { /* ... 大量データ */ },
en: { /* ... */ },
};
import defer * as i18n from "./i18n-resources.js";
function getMessage(locale: string, key: string): string {
return i18n.resources[locale]?.[key] ?? "MISSING";
}
言語設定が変わったタイミングで初めてリソースが評価されるので、初期表示が高速になります。
import deferの注意点と制限
top-level awaitとの非互換
import deferで読み込んだモジュールや、その依存がtop-level awaitを使っている場合はすぐ評価されます。プロパティアクセスは同期でなければならず、非同期の評価は先に終わっている必要があるからです。
// async-module.ts
const response = await fetch("/config.json");
export const config = await response.json();
// main.ts
import defer * as cfg from "./async-module.js";
// top-level awaitを含むのでdeferしてもすぐに評価が開始される
ランタイムサポートの状況
import deferはECMAScriptのStage 3提案で、2026年9月時点でネイティブ対応するランタイムはありません。Chrome/V8チームが実装に興味を示している段階です。
バンドラの対応も進むでしょうから、今のうちに構文と使い方を押さえておいて損はありません。
読み込みは即時行われる
import deferが遅延するのは評価だけです。解決・取得・解析は静的importと同じタイミングなので、ネットワーク経由の遅延ローディングには従来通り動的importが必要です。
実測メモ: 型チェックの時点で --module の指定が効いてきます。TS 5.9.3 で確認したところ、nodenext だと error TS18060: Deferred imports are only supported when the '--module' flag is set to 'esnext' or 'preserve'. で弾かれ、esnext にすると通ります。ビルドツールの設定が nodenext のままの場合は、ここで一度ハマるので先に確認しておきましょう。
まとめ
import deferは静的importのシンプルさ(同期処理)を保ったまま、動的importのメリット(評価の遅延)を得られる構文ですね。
| シチュエーション | おすすめのimport方式 |
|---|---|
| 即時必要なモジュール | 静的import |
| 条件によって読み込む(非同期OK) | 動的import |
| 読み込みは事前、評価だけ遅延したい(同期のまま) | import defer |
「重い初期化処理を持つモジュール」「プラットフォーム固有の実装」「巨大な設定データ」を扱うプロジェクトなら、import deferを視野に入れた設計を始めてみてもいいかもしれませんね。
【広告】お名前.comならドメイン取得が格安。![]()
検証環境
| OS | Windows 11 (build 10.0.26200) |
|---|---|
| CPU | AMD Ryzen 9 PRO 8945HS w/ Radeon 780M Graphics |
| メモリ | 28GB |
| 言語/ツール | TypeScript 5.9.3(npx経由) / Node.js 22.23.2 |
| 使用コマンド | npx -p typescript@5.9.3 tsc –noEmit –module nodenext app.ts |
| 測定日 | 2026-09-17 |
上記の環境で実際に実行して確認した結果です。環境が異なる場合は挙動が変わることがあります。

参考
本文の記述は以下の一次情報を確認して書いています。
- TypeScript 公式リリースノート — 5.9(import defer)
- TypeScript 公式ブログ — Announcing TypeScript 5.9
- TC39 提案 — proposal-defer-import-eval
- TC39 提案仕様 — Deferred Imports Evaluation(Stage 3 Draft)
あわせて読みたい
- 【TypeScript】TS 7 vs 6.0 型チェック速度を実測比較2026
- 【TypeScript】TypeScript 6.0 移行ガイド — 5.x からの手順と新機能
- 【pnpm】ERR_PNPM_IGNORED_BUILDS の直し方 — allowBuilds へ移行
- 【Node.js】ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX の直し方
【広告】このサイトはConoHa WINGで運営しています。安定した高速サーバーで快適にブログを書けています。いつもありがとう!!![]()

コメント