T-CREATOR

ESLint エラーのよくある原因とその解決法

ESLint エラーのよくある原因とその解決法

ESLint を使用していると、様々なエラーに遭遇することがありますね。特に開発初期段階では、エラーメッセージの意味がわからず困ってしまうことも多いのではないでしょうか。

ESLint エラーは一見複雑に見えますが、実は典型的なパターンがあります。これらのパターンを理解することで、エラーが発生した際に素早く原因を特定し、適切な解決策を見つけることができるようになります。本記事では、実際の開発現場でよく遭遇する ESLint エラーを分類し、それぞれの原因と具体的な解決方法をご紹介します。

構文エラーの原因と対処法

構文エラーは、JavaScript や TypeScript の基本的な文法ルールに違反した際に発生するエラーです。ESLint はコードを解析する際に、まず構文の正しさをチェックします。

パースエラーの典型例

最も頻繁に遭遇するのが、パーサーがコードを正しく解釈できない場合のエラーです。

javascript// エラー例:Unexpected token
const message = "Hello World"
console.log(message

上記のコードでは、console.logの閉じ括弧が不足しているため、以下のようなエラーが発生します。

luaParsing error: Unexpected end of input

このエラーの解決方法は、不足している括弧を追加することです。

javascript// 修正後
const message = 'Hello World';
console.log(message);

括弧・セミコロンの不整合

JavaScript 開発では、括弧やセミコロンの不整合によるエラーも頻発します。

javascript// エラー例:括弧の不整合
function calculateTotal(price, tax) {
  return price * (1 + tax;
}

このコードでは、括弧の開閉が正しく対応していないため、以下のエラーが発生します。

goParsing error: Unexpected token ';'

正しく修正するには、括弧のペアを確認します。

javascript// 修正後
function calculateTotal(price, tax) {
  return price * (1 + tax);
}

予約語の誤用

JavaScript の予約語を変数名や関数名として使用すると、構文エラーが発生します。

javascript// エラー例:予約語の使用
const class = "my-class";
function return() {
  console.log("test");
}

このコードではclassreturnという予約語を使用しているため、以下のエラーが発生します。

goParsing error: Unexpected token 'class'
Parsing error: Unexpected token 'return'

解決方法は、予約語以外の名前を使用することです。

javascript// 修正後
const className = 'my-class';
function returnHome() {
  console.log('test');
}

変数・スコープ関連エラー

変数のスコープに関するエラーは、コードの保守性と可読性に大きく影響します。ESLint はこれらの問題を早期に発見してくれます。

未定義変数の検出

最も基本的なエラーの一つが、定義されていない変数を使用した場合のエラーです。

javascript// エラー例:未定義変数の使用
function greetUser() {
  console.log(userName); // userNameが定義されていない
}

ESLint は以下のエラーを表示します。

perl'userName' is not defined. (no-undef)

解決方法は、変数を適切に定義することです。

javascript// 修正後
function greetUser() {
  const userName = '太郎';
  console.log(userName);
}

使用されていない変数

定義したが使用されていない変数も、ESLint がチェックしてくれます。

javascript// エラー例:使用されていない変数
function processData() {
  const result = [];
  const unusedVariable = 'not used'; // 使用されていない

  return result;
}

以下のエラーが表示されます。

python'unusedVariable' is assigned a value but never used. (no-unused-vars)

不要な変数を削除するか、実際に使用することで解決します。

javascript// 修正後:不要な変数を削除
function processData() {
  const result = [];

  return result;
}

スコープ外参照エラー

ブロックスコープやクロージャーに関する理解不足から発生するエラーです。

javascript// エラー例:スコープ外参照
function setupCounter() {
  if (true) {
    let count = 0;
  }
  console.log(count); // countはスコープ外
}

ESLint は以下のエラーを出力します。

perl'count' is not defined. (no-undef)

変数のスコープを適切に管理することで解決できます。

javascript// 修正後:適切なスコープで定義
function setupCounter() {
  let count = 0; // 関数スコープで定義

  if (true) {
    count = 1;
  }
  console.log(count);
}

import/export エラーの解決

モジュールシステムに関するエラーは、現代の JavaScript 開発で頻繁に発生します。特に ES6 の import/export 構文や CommonJS との混在時に問題が起こりやすくなります。

モジュール解決エラー

存在しないモジュールをインポートしようとした場合のエラーです。

javascript// エラー例:存在しないモジュール
import { nonExistentFunction } from './utils';

ESLint は以下のエラーを表示します。

vbnetUnable to resolve path to module './utils'. (import/no-unresolved)

解決方法は、正しいパスを指定するか、必要なファイルを作成することです。

javascript// 修正後:正しいパスを指定
import { helperFunction } from './utils/helpers';

対応するutils​/​helpers.jsファイルも作成します。

javascript// utils/helpers.js
export function helperFunction() {
  return 'Helper function';
}

循環 import 問題

モジュール同士が相互にインポートしている場合の循環参照エラーです。

javascript// moduleA.js
import { functionB } from './moduleB';

export function functionA() {
  return functionB();
}

// moduleB.js
import { functionA } from './moduleA'; // 循環参照

export function functionB() {
  return functionA();
}

ESLint は以下の警告を出します。

sqlDependency cycle detected. (import/no-cycle)

解決方法は、依存関係を整理し、共通の機能を別のモジュールに分離することです。

javascript// common.js - 共通機能を分離
export function sharedFunction() {
  return 'Shared logic';
}

// moduleA.js
import { sharedFunction } from './common';

export function functionA() {
  return `A: ${sharedFunction()}`;
}

// moduleB.js
import { sharedFunction } from './common';

export function functionB() {
  return `B: ${sharedFunction()}`;
}

デフォルト export の誤用

デフォルトエクスポートと名前付きエクスポートの混同によるエラーです。

javascript// utils.js - デフォルトエクスポート
export default function calculate(a, b) {
  return a + b;
}

// main.js - 誤ったインポート方法
import { calculate } from './utils'; // エラー

以下のエラーが発生します。

kotlin'calculate' is not exported by module './utils'. (import/named)

デフォルトエクスポートは中括弧なしでインポートします。

javascript// 修正後:正しいインポート方法
import calculate from './utils';

// 使用例
const result = calculate(5, 3);
console.log(result); // 8

TypeScript 連携時の頻出エラー

TypeScript と ESLint を組み合わせて使用する際には、型安全性に関する特有のエラーが発生することがあります。

型定義不整合

TypeScript の型定義と ESLint ルールが競合する場合のエラーです。

typescript// エラー例:型定義の不整合
interface User {
  id: number;
  name: string;
  email?: string;
}

function createUser(userData: any): User {
  // any型の使用
  return {
    id: userData.id,
    name: userData.name,
    email: userData.email,
  };
}

ESLint は以下のエラーを表示します。

lessUnexpected any. Specify a different type. (@typescript-eslint/no-explicit-any)

適切な型定義を使用することで解決します。

typescript// 修正後:適切な型定義
interface UserInput {
  id: number;
  name: string;
  email?: string;
}

interface User {
  id: number;
  name: string;
  email?: string;
}

function createUser(userData: UserInput): User {
  return {
    id: userData.id,
    name: userData.name,
    email: userData.email,
  };
}

any 型の不適切な使用

TypeScript の利点を損なうany型の使用に対するエラーです。

typescript// エラー例:any型の多用
function processData(data: any[]): any {
  return data.map((item: any) => {
    return item.value * 2;
  });
}

以下のエラーが発生します。

lessUnexpected any. Specify a different type. (@typescript-eslint/no-explicit-any)

具体的な型を定義することで型安全性を向上させます。

typescript// 修正後:具体的な型定義
interface DataItem {
  value: number;
  label: string;
}

function processData(data: DataItem[]): number[] {
  return data.map((item: DataItem) => {
    return item.value * 2;
  });
}

厳密性チェックエラー

TypeScript の厳密モードでの null チェックエラーです。

typescript// エラー例:null/undefinedチェック不足
function getUserName(user: User | null): string {
  return user.name; // nullの可能性がある
}

以下のエラーが表示されます。

lessObject is possibly 'null'. (@typescript-eslint/no-unsafe-member-access)

適切な null チェックを追加します。

typescript// 修正後:nullチェックを追加
function getUserName(user: User | null): string {
  if (user === null) {
    return 'Unknown';
  }
  return user.name;
}

// より簡潔な書き方
function getUserNameShort(user: User | null): string {
  return user?.name ?? 'Unknown';
}

React/JSX 特有のエラー対応

React 開発では、JSX の構文や Hooks の使用ルールに関する特有のエラーが発生します。これらのエラーを理解することで、より安全な React アプリケーションを構築できます。

Hooks 使用ルール違反

React の Hooks には「Hooks のルール」という重要な制約があります。

jsx// エラー例:条件分岐内でのHooks使用
function UserProfile({ userId }) {
  if (!userId) {
    return <div>ユーザーIDが必要です</div>;
  }

  const [user, setUser] = useState(null); // ルール違反

  return <div>{user?.name}</div>;
}

以下のエラーが発生します。

sqlReact Hook "useState" is called conditionally. React Hooks must be called in the exact same order every time. (react-hooks/rules-of-hooks)

Hooks は必ずコンポーネントのトップレベルで呼び出す必要があります。

jsx// 修正後:Hooksをトップレベルで使用
function UserProfile({ userId }) {
  const [user, setUser] = useState(null);

  if (!userId) {
    return <div>ユーザーIDが必要です</div>;
  }

  return <div>{user?.name}</div>;
}

JSX 構文エラー

JSX の記述方法に関するエラーです。

jsx// エラー例:閉じタグの不備
function WelcomeMessage() {
  return (
    <div>
      <h1>ようこそ!</h1>
      <p>サイトへお越しいただき、ありがとうございます。
    </div>
  );
}

以下のエラーが表示されます。

goParsing error: Unterminated JSX contents

すべての JSX タグを適切に閉じる必要があります。

jsx// 修正後:適切にタグを閉じる
function WelcomeMessage() {
  return (
    <div>
      <h1>ようこそ!</h1>
      <p>サイトへお越しいただき、ありがとうございます。</p>
    </div>
  );
}

props 型チェックエラー

TypeScript と React を組み合わせた際の、props 型定義に関するエラーです。

tsx// エラー例:props型の不整合
interface ButtonProps {
  label: string;
  onClick: () => void;
}

function CustomButton(props) {
  // 型定義なし
  return (
    <button onClick={props.onClick}>{props.label}</button>
  );
}

以下のエラーが発生します。

lessParameter 'props' implicitly has an 'any' type. (@typescript-eslint/no-implicit-any)

適切な型定義を追加することで解決します。

tsx// 修正後:適切な型定義
interface ButtonProps {
  label: string;
  onClick: () => void;
}

function CustomButton({ label, onClick }: ButtonProps) {
  return <button onClick={onClick}>{label}</button>;
}

// 使用例
function App() {
  const handleClick = () => {
    console.log('ボタンがクリックされました');
  };

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

さらに、useEffect の依存配列に関するエラーも頻発します。

tsx// エラー例:依存配列の不備
function UserData({ userId }) {
  const [user, setUser] = useState(null);

  useEffect(() => {
    fetchUser(userId).then(setUser);
  }, []); // userIdが依存配列にない

  return <div>{user?.name}</div>;
}

以下の警告が表示されます。

bashReact Hook useEffect has a missing dependency: 'userId'. (react-hooks/exhaustive-deps)

必要な依存関係をすべて配列に含める必要があります。

tsx// 修正後:適切な依存配列
function UserData({ userId }) {
  const [user, setUser] = useState(null);

  useEffect(() => {
    fetchUser(userId).then(setUser);
  }, [userId]); // userIdを依存配列に追加

  return <div>{user?.name}</div>;
}

まとめ

ESLint エラーは最初は複雑に見えますが、パターンを理解すれば確実に解決できるものばかりです。構文エラーから始まり、変数スコープ、モジュールシステム、TypeScript 連携、React 開発まで、それぞれに特徴的なエラーパターンがあることがおわかりいただけたでしょう。

重要なのは、エラーメッセージをしっかりと読み、ルール名から原因を推測することです。また、エラーが発生した際は慌てず、本記事で紹介したような基本的なパターンに当てはめて考えてみてください。

継続的に ESLint を活用することで、コード品質の向上だけでなく、JavaScript/TypeScript/React の理解も深まります。エラーを恐れず、学習の機会として捉えることで、より良いコードを書けるようになるはずです。

関連リンク