TypeScriptでよく遭遇する「ES Modules」と「CommonJS」のモジュールシステムに関する問題について、具体的な解決方法を解説します。

モジュールシステムの基本的な違い

ES Modules(ESM)とCommonJS(CJS)は、JavaScriptにおける2つの主要なモジュールシステムです。

ES Modules の特徴

// エクスポート
export const hello = () => console.log('Hello');
export default class User {}

// インポート
import { hello } from './module';
import User from './module';

CommonJS の特徴

// エクスポート
const hello = () => console.log('Hello');
module.exports = { hello };

// インポート
const { hello } = require('./module');

TypeScriptでの設定方法

`tsconfig.json`でモジュールシステムを指定できます:

{
  "compilerOptions": {
    "module": "ESNext",  // ES Modules用
    // または
    "module": "CommonJS" // CommonJS用
  }
}

よくある問題と解決策

1. 混在による問題

問題

// ESMとCJSの混在
import express from 'express';
const lodash = require('lodash');

解決策

// 統一したインポート方式を使用
import express from 'express';
import lodash from 'lodash';

2. パッケージの互換性問題

問題

// Type Error: Cannot use import statement outside a module
import { someFunction } from 'some-package';

解決策

`package.json`に以下を追加:

{
  "type": "module"
}

3. 動的インポートの扱い

ESM方式

const module = await import('./module.js');

CJS方式

const module = require('./module.js');

ベストプラクティス

1. プロジェクト全体で一貫したモジュールシステムを使用

- 新規プロジェクトではES Modulesを推奨

- レガシープロジェクトではCommonJSを維持

2. package.jsonの適切な設定

{
  "type": "module",  // ES Modules用
  "exports": {
    ".": {
      "import": "./dist/index.js",
      "require": "./dist/index.cjs"
    }
  }
}

3. 拡張子の明示的な指定

// 推奨
import { function } from './module.js';

モジュールシステムの選択基準

1. ES Modulesを選ぶ場合

- 最新のNode.js環境を使用

- ブラウザ環境での実行が主

- Tree Shakingを活用したい

2. CommonJSを選ぶ場合

- レガシーなNode.js環境との互換性が必要

- 既存のCommonJSプロジェクトとの統合

- 動的なモジュール解決が必要

まとめ

  • ES ModulesとCommonJSの違いを理解し、プロジェクトに適したものを選択
  • 一貫したモジュールシステムの使用で問題を回避
  • 適切な設定とベストプラクティスの遵守が重要

これらの知識を活用することで、TypeScriptプロジェクトでのモジュールシステムに関する問題を効果的に解決できます。