TypeScript「Module can only be default-imported using the allowSyntheticDefaultImports flag」エラーの修正方法

beginner🔵 TypeScript2026-05-04| TypeScript 2.x〜5.x、Node.jsプロジェクト、React/Vite/Webpackアプリ、すべてのOS

Error Message

Module '...' can only be default-imported using the 'allowSyntheticDefaultImports' flag
#typescript#tsconfig#import

エラーの内容

クリーンなデフォルトインポートを書いたとたん、TypeScript がすぐに警告を出します:

Module 'express' can only be default-imported using the 'allowSyntheticDefaultImports' flag
Module 'react' can only be default-imported using the 'allowSyntheticDefaultImports' flag
Module 'lodash' can only be default-imported using the 'allowSyntheticDefaultImports' flag

このエラーは、新しい npm パッケージを追加したとき、TypeScript の設定を厳しくしたとき、または既存の JS プロジェクトを TypeScript に移行したときに発生しやすいです。

原因

expresslodashmoment などの古い CommonJS パッケージには、本物の ES モジュールのデフォルトエクスポートがありません。これらは module.exports = ... を通じてすべてを公開しています。TypeScript はこの不一致を検出し、次のような書き方を許可しません:

import express from 'express'; // ❌ フラグなしではエラー

allowSyntheticDefaultImports フラグは、TypeScript が「module.exports をデフォルトエクスポートとして扱う」ことを許可するための設定です。これは型チェックのみの設定であり、コンパイル後の JavaScript 出力はまったく変わりません。

知っておくべき重要な点として、esModuleInterop を有効にすると、allowSyntheticDefaultImports も自動的に有効になります。詳細は修正方法 2 で説明します。

修正方法 1 — tsconfig.json で allowSyntheticDefaultImports を有効にする(推奨)

tsconfig.json を開き、compilerOptions にフラグを追加します:

{
  "compilerOptions": {
    "allowSyntheticDefaultImports": true,
    // ... その他のオプション
  }
}

保存して tsc を再実行してください。エラーが消えます。この1行の変更で、大多数のプロジェクトの問題が解決します。

修正方法 2 — esModuleInterop を使用する(Node.js/CommonJS プロジェクトにより適した方法)

esModuleInterop はアップグレード版と考えてください。allowSyntheticDefaultImports が行うすべてのことに加え、出力された JavaScript で CommonJS の相互運用を正しく機能させるランタイムヘルパーも注入します。Node.js プロジェクトや CommonJS パッケージをバンドルする場合は、こちらを使用することをお勧めします:

{
  "compilerOptions": {
    "esModuleInterop": true,
    // esModuleInterop が true の場合、allowSyntheticDefaultImports も自動的に true になります
  }
}

これを設定すると、デフォルトインポートが正常に動作します:

import express from 'express';     // ✅
import React from 'react';         // ✅
import _ from 'lodash';            // ✅
import moment from 'moment';       // ✅

修正方法 3 — 名前空間インポートを使用する(tsconfig を変更せずに)

TypeScript の設定を変更できない場合は、代わりに名前空間インポートを使用してください:

// 以下の代わりに:
import express from 'express'; // ❌

// こちらを使用:
import * as express from 'express'; // ✅

これが機能するのは、モジュールが何かをエクスポートしているからです — ただし、名前付きデフォルトとしてではありません。名前空間インポートは module.exports オブジェクト全体を取得します。ただし注意点として、見た目が少し奇妙であり、一部のライブラリの型定義はデフォルトインポート構文を前提としています。この不一致により、コードの他の場所で二次的な型エラーが発生する可能性があります。

修正の確認

コンパイラを実行してすべてが正常であることを確認します:

# tsc を直接使用する場合
npx tsc --noEmit

# ビルドスクリプトがある場合
npm run build

Vite または CRA プロジェクトの場合は、ファイルを保存するだけです。開発サーバーが自動的に再コンパイルし、ブラウザの赤いエラーバナーは1〜2秒以内に消えるはずです。

現在有効なフラグを確認したい場合は、次のコマンドを実行します:

npx tsc --showConfig | grep -E 'allowSyntheticDefaultImports|esModuleInterop'

次のように表示されるはずです:

"allowSyntheticDefaultImports": true,
"esModuleInterop": true,

よくあるシナリオ:Create React App / Vite

CRA と Vite はどちらも、生成された tsconfig.json にデフォルトで esModuleInterop: true が含まれています。そのため、新規作成した CRA または Vite プロジェクトでこのエラーが発生する場合は、生成後に何かが変更されています。フラグが手動で削除されたか、それを上書きするベース設定を継承しているかのいずれかです。両方のファイルを確認してください:

{
  "extends": "./tsconfig.base.json", // ← このファイルも確認
  "compilerOptions": { ... }
}

よくあるシナリオ:JavaScript からの移行

.js ファイルを .ts にリネームして TypeScript を初めて起動した場合、最初のコンパイル時にこのエラーが発生します。expresslodashmoment などのパッケージがすべてこのエラーを引き起こします。移行設定の一環として tsconfig.jsonesModuleInterop: true を追加してください — これにより、すべての問題を一度に解決できます。

クイックヒント

  • allowSyntheticDefaultImports: true 単独よりも esModuleInterop: true を優先してください — CommonJS の相互運用においてより安全であり、TypeScript チームの推奨でもあります。
  • 他者が使用するライブラリを作成している場合は、esModuleInterop の使用に注意してください。これは出力された JavaScript でのインポートの処理方法を変更するため、同じ設定を使用していないユーザーが驚くことがあります。
  • 一部のパッケージ(@types/node を含む)は、適切な ES デフォルトエクスポートを持つように更新されています。メンテナンスが行き届いたパッケージでもこのエラーが発生する場合、原因はほぼ確実に型定義ではなく tsconfig にあります。
  • 同じモジュールに対して名前空間インポート(import * as X from '...')とデフォルトインポート(import X from '...')を混在させないでください — どちらか一方のスタイルを選び、ファイル全体で統一してください。

Related Error Notes