T-CREATOR

ESLint で Global 変数を正しく扱う方法

ESLint で Global 変数を正しく扱う方法

ESLint でコードを書いていると、突然「'console' is not defined」や「'window' is not defined」というエラーに遭遇して、「あれ?これって普通に使えるはずなのに...」と困惑した経験はありませんか?

実は、これらのエラーは ESLint がグローバル変数を認識していないことが原因です。今回は、ESLint でグローバル変数を正しく扱う方法について、実際のエラーケースから解決策まで詳しく解説していきます。

背景

ESLint が厳格な理由

ESLint は、JavaScript の静的解析ツールとして、コードの品質を保つために非常に厳格なルールを適用します。特に、未定義の変数の使用は重大なバグの原因となるため、デフォルトで厳しくチェックされます。

しかし、JavaScript 開発では避けて通れないのがグローバル変数の存在です。ブラウザ環境ではwindowdocumentconsoleなどが、Node.js 環境ではprocessglobalBufferなどが標準で利用できますが、これらは ESLint にとっては「どこからともなく現れた未定義の変数」として認識されてしまいます。

開発現場での実際の困りごと

多くの開発者が経験する典型的な困りごとをご紹介しましょう。

javascript// ブラウザ環境でのよくあるコード
console.log('デバッグ情報'); // ESLintエラー!
window.location.href = '/login'; // ESLintエラー!
document.getElementById('app'); // ESLintエラー!

// Node.js環境でのよくあるコード
process.env.NODE_ENV; // ESLintエラー!
global.myGlobalVar = 'test'; // ESLintエラー!

このような基本的なコードでエラーが発生すると、開発の流れが止まってしまい、非常にストレスフルな体験となります。

課題

実際に発生するエラーコード

ESLint でグローバル変数を使用した際に発生する代表的なエラーコードをご紹介します。これらのエラーコードを覚えておくと、問題の特定が素早く行えます。

no-undef エラー

最も頻繁に遭遇するエラーです。

javascript// エラーコード例
console.log('Hello World');
bash1:1  error  'console' is not defined  no-undef

no-global-assign エラー

グローバル変数を再代入しようとした際に発生します。

javascript// エラーコード例
window = {};
bash1:1  error  Read-only global 'window' should not be modified  no-global-assign

no-implicit-globals エラー

スクリプトファイルでグローバル変数を作成する際に発生します。

javascript// エラーコード例
var myGlobalVar = 'test';
bash1:1  error  Implicit global variable, assign as global property instead  no-implicit-globals

開発者が陥りがちな対処法の問題点

多くの開発者が最初に試す対処法には、実は問題があります。

問題のある対処法 1: エラーの無視

javascript// 悪い例:エラーを無視するだけ
/* eslint-disable no-undef */
console.log('Hello World');

これは根本的な解決にならず、本当に未定義の変数を使った場合のエラーも見逃してしまいます。

問題のある対処法 2: 無制限なグローバル許可

javascript// 悪い例:すべてのグローバル変数を許可
/* global console, window, document, process, global, Buffer */

必要以上にグローバル変数を許可すると、タイポや実際の未定義変数の検出ができなくなります。

解決策

1. env(環境)設定による解決

最も推奨される解決方法は、ESLint のenv設定を使用することです。これにより、特定の環境で利用可能なグローバル変数を一括で許可できます。

.eslintrc.js での設定

javascriptmodule.exports = {
  env: {
    browser: true, // ブラウザ環境のグローバル変数を許可
    node: true, // Node.js環境のグローバル変数を許可
    es2021: true, // ES2021のグローバル変数を許可
  },
  // その他の設定...
};

この設定により、以下のグローバル変数が自動的に認識されます:

環境設定利用可能になるグローバル変数(例)
browserwindow, document, console, alert, confirm
nodeprocess, global, Buffer, **dirname, **filename
es2021Promise, Symbol, Map, Set, WeakMap

package.json での設定

json{
  "eslintConfig": {
    "env": {
      "browser": true,
      "node": true,
      "es2021": true
    }
  }
}

2. globals 設定による個別対応

特定のグローバル変数のみを許可したい場合は、globals設定を使用します。

読み取り専用グローバル変数の設定

javascriptmodule.exports = {
  globals: {
    console: 'readonly', // 読み取り専用で許可
    window: 'readonly', // 読み取り専用で許可
    document: 'readonly', // 読み取り専用で許可
    process: 'readonly', // 読み取り専用で許可
  },
  // その他の設定...
};

書き込み可能なグローバル変数の設定

javascriptmodule.exports = {
  globals: {
    myGlobalVar: 'writable', // 書き込み可能で許可
    APP_CONFIG: 'writable', // 書き込み可能で許可
  },
  // その他の設定...
};

3. TypeScript 環境での対応

TypeScript 環境では、型定義の問題も考慮する必要があります。

@typescript-eslint/parser の設定

javascriptmodule.exports = {
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaVersion: 2021,
    sourceType: 'module',
    ecmaFeatures: {
      jsx: true,
    },
  },
  env: {
    browser: true,
    node: true,
    es2021: true,
  },
  // その他の設定...
};

TypeScript 用のグローバル変数定義

typescript// globals.d.ts
declare global {
  interface Window {
    myCustomProperty: string;
  }

  var myGlobalFunction: () => void;
}

export {};

4. インラインコメントによる部分的対応

特定の行でのみグローバル変数を使用する場合は、インラインコメントを使用します。

単一行での対応

javascript/* global console */
console.log('Hello World');

複数行での対応

javascript/* global console, window, document */
console.log('Hello World');
window.location.href = '/login';
document.getElementById('app');

eslint-disable-next-line の使用

javascript// eslint-disable-next-line no-undef
console.log('Hello World');

具体例

React + TypeScript プロジェクトでの設定例

React + TypeScript 環境でよく使用される設定をご紹介します。

.eslintrc.js の完全な設定例

javascriptmodule.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true,
    jest: true,
  },
  extends: [
    'eslint:recommended',
    '@typescript-eslint/recommended',
    'plugin:react/recommended',
    'plugin:react-hooks/recommended',
  ],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 12,
    sourceType: 'module',
  },
  plugins: ['react', '@typescript-eslint'],
  globals: {
    React: 'readonly',
    JSX: 'readonly',
  },
  rules: {
    'no-undef': 'error',
    'no-unused-vars': 'off',
    '@typescript-eslint/no-unused-vars': 'error',
  },
};

対応する package.json の dependencies

json{
  "devDependencies": {
    "@typescript-eslint/eslint-plugin": "^6.0.0",
    "@typescript-eslint/parser": "^6.0.0",
    "eslint": "^8.0.0",
    "eslint-plugin-react": "^7.32.0",
    "eslint-plugin-react-hooks": "^4.6.0"
  }
}

この設定により、以下のコードがエラーなく動作します:

typescript// ブラウザ環境のグローバル変数
console.log('デバッグ情報');
window.location.href = '/dashboard';
document.title = 'My App';

// React関連のグローバル変数
const App: React.FC = () => {
  return <div>Hello World</div>;
};

Node.js + Express プロジェクトでの設定例

Node.js 環境でのサーバーサイド開発における設定例です。

.eslintrc.js の設定

javascriptmodule.exports = {
  env: {
    node: true,
    es2021: true,
    commonjs: true,
  },
  extends: ['eslint:recommended'],
  parserOptions: {
    ecmaVersion: 12,
    sourceType: 'module',
  },
  globals: {
    __dirname: 'readonly',
    __filename: 'readonly',
    exports: 'writable',
    module: 'writable',
    require: 'readonly',
  },
  rules: {
    'no-undef': 'error',
    'no-unused-vars': 'error',
  },
};

動作確認用のコード例

javascript// Node.js環境のグローバル変数
console.log('サーバー起動中...');
console.log('現在のディレクトリ:', __dirname);
console.log('Node.js バージョン:', process.version);

// Express の設定
const express = require('express');
const app = express();
const PORT = process.env.PORT || 3000;

app.listen(PORT, () => {
  console.log(`サーバーがポート ${PORT} で起動しました`);
});

Next.js プロジェクトでの環境別設定

Next.js プロジェクトでは、サーバーサイドとクライアントサイドで異なるグローバル変数が必要となります。

.eslintrc.js の設定

javascriptmodule.exports = {
  env: {
    browser: true,
    es2021: true,
    node: true,
  },
  extends: ['eslint:recommended', 'next/core-web-vitals'],
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 12,
    sourceType: 'module',
  },
  globals: {
    React: 'readonly',
    JSX: 'readonly',
  },
  overrides: [
    {
      files: [
        'pages/**/*.js',
        'pages/**/*.ts',
        'pages/**/*.tsx',
      ],
      env: {
        browser: true,
        node: true,
      },
    },
    {
      files: ['lib/**/*.js', 'lib/**/*.ts'],
      env: {
        node: true,
      },
    },
  ],
};

実際の使用例

javascript// pages/index.js (クライアントサイド)
export default function Home() {
  const handleClick = () => {
    // ブラウザ環境のグローバル変数
    window.alert('ボタンがクリックされました!');
    console.log('クリックイベント発生');
  };

  return (
    <button onClick={handleClick}>
      クリックしてください
    </button>
  );
}

// pages/api/hello.js (サーバーサイド)
export default function handler(req, res) {
  // Node.js環境のグローバル変数
  console.log('API呼び出し:', process.env.NODE_ENV);

  res.status(200).json({
    message: 'Hello from API',
    timestamp: new Date().toISOString()
  });
}

実践的なトラブルシューティング

開発中によく遭遇する問題と、その解決方法をご紹介します。

問題 1: jQuery 使用時のエラー

javascript// エラーが発生するコード
$('#myElement').click(function () {
  console.log('クリックされました');
});
bash1:1  error  '$' is not defined  no-undef

解決方法:

javascript// .eslintrc.js
module.exports = {
  env: {
    browser: true,
    jquery: true, // jQuery環境を有効化
  },
  // または globals で個別設定
  globals: {
    $: 'readonly',
    jQuery: 'readonly',
  },
};

問題 2: Web API 使用時のエラー

javascript// エラーが発生するコード
fetch('/api/data')
  .then((response) => response.json())
  .then((data) => console.log(data));
bash1:1  error  'fetch' is not defined  no-undef

解決方法:

javascript// .eslintrc.js
module.exports = {
  env: {
    browser: true,
    es2021: true, // fetch APIを含むES2021の機能を有効化
  },
  // または globals で個別設定
  globals: {
    fetch: 'readonly',
  },
};

問題 3: テスト環境でのエラー

javascript// エラーが発生するテストコード
describe('テストスイート', () => {
  it('正常に動作する', () => {
    expect(true).toBe(true);
  });
});
bash1:1  error  'describe' is not defined  no-undef
2:3  error  'it' is not defined  no-undef
3:5  error  'expect' is not defined  no-undef

解決方法:

javascript// .eslintrc.js
module.exports = {
  env: {
    browser: true,
    node: true,
    jest: true, // Jest環境を有効化
    mocha: true, // Mocha環境を有効化(必要に応じて)
  },
  // または overrides で特定ディレクトリのみ設定
  overrides: [
    {
      files: ['**/*.test.js', '**/*.spec.js'],
      env: {
        jest: true,
      },
    },
  ],
};

パフォーマンス最適化のコツ

ESLint のグローバル変数設定は、パフォーマンスにも影響を与えます。

最適化のポイント

  1. 必要な環境のみを有効化
javascript// 良い例:必要な環境のみ指定
module.exports = {
  env: {
    browser: true, // ブラウザ環境のみ
  },
};

// 悪い例:不要な環境まで指定
module.exports = {
  env: {
    browser: true,
    node: true,
    worker: true,
    serviceworker: true,
    // 使わない環境まで指定するのは非効率
  },
};
  1. overrides の活用
javascriptmodule.exports = {
  // 基本設定
  env: {
    es2021: true,
  },
  overrides: [
    {
      // ブラウザ用ファイルのみに適用
      files: ['src/**/*.js'],
      env: {
        browser: true,
      },
    },
    {
      // Node.js用ファイルのみに適用
      files: ['server/**/*.js'],
      env: {
        node: true,
      },
    },
  ],
};

まとめ

ESLint でグローバル変数を正しく扱うことは、コードの品質を保ちながら開発効率を向上させる重要なスキルです。

今回ご紹介した内容を整理すると:

推奨される解決方法の優先順位

  1. env 設定による環境指定(最も推奨)
  2. globals 設定による個別指定
  3. overrides による詳細な制御
  4. インラインコメントによる部分的対応(最小限に使用)

開発現場での実践ポイント

  • チーム共通の ESLint 設定を作成し、統一されたルールで開発を行う
  • プロジェクトの特性に応じた環境設定を適切に選択する
  • 過度にグローバル変数を許可しないことで、本来の ESLint の恩恵を受ける
  • エラーメッセージを恐れずに、適切な設定で解決していく

ESLint のグローバル変数設定をマスターすることで、開発中のストレスが大幅に軽減され、より集中してコードの本質的な部分に取り組めるようになります。

特に、実際のプロジェクトでは複数の環境(ブラウザ、Node.js、テスト環境など)を組み合わせて使用することが多いため、overrides 機能を使った詳細な設定が重要になります。

皆さんも、今回ご紹介した方法を実際のプロジェクトで試してみて、より快適な JavaScript/TypeScript 開発を実現してください。きっと、「あのエラーに悩まされる時間」が大幅に短縮されるはずです!

関連リンク