🎨

Cannot find module '〇〇.svg or its corresponding type declarations の解決

に公開

発生したエラー

error TS2307: Cannot find module '@/svgs/icons/〇〇.svg' or its corresponding type declarations.

import 〇〇 from "@/svgs/icons/〇〇.svg";
                            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

これは Next.js プロジェクトで SVG ファイルをインポートする際に、TypeScript がそのモジュールの型定義を見つけられないというエラーです。複数の SVG ファイルのインポートで同様のエラーが発生しました。

エラーの発生状況

  • biome を採用しているプロジェクト
  • noUndeclaredValue(React が宣言されていないというエラー)の無視コメントを削除
  • import type React from "react"をファイルに追加していったところ発生
  • このプロジェクトでは SVG をモジュール化して使うために@svgr/webpackを採用
  • SVG の型定義ファイル(index.d.ts)が必要な状況

エラーの原因

結論、index.d.tsファイルの import 文追加が直接的な原因でした。

このエラーを考える時に必要な知識は次の 2 つです:

  1. SVG ファイルの型定義の不在: TypeScript はデフォルトで SVG ファイルをモジュールとして認識しません。

  2. 型定義ファイルの書き方の問題: 特に重要なポイントとして、型定義ファイル(.d.ts)でimport文を使うと、そのファイルはグローバル宣言ではなく通常のモジュール宣言として扱われます。

問題のindex.d.tsファイルのコード:

// index.d.ts
import type React from "react";
declare module "*.svg" {
  const content: React.FC<React.SVGProps<SVGElement>>;
  export default content;
}

この書き方だと、import文によってファイルがモジュールとして扱われ、グローバルな型定義として適用されなくなります。

解決方法

当初は以下のようにして解決しようとしていたのですが、biome の format で import 文が削除されてしまいました。

// index.d.ts
declare module "*.svg" {
  import type React from "react";
  const content: React.FC<React.SVGProps<SVGElement>>;
  export default content;
}

困ったので、biome-ignore コメントを残そうかと思いましたが、Stack Overflowで対処法を発見しました。

要は、import()型構文を使用すれば回避できるというものです。以下のようにファイルを修正したところ、TypeScript のエラーが解消されました:

// index.d.ts
declare module "*.svg" {
  const content: import("react").FC<import("react").SVGProps<SVGElement>>;
  export default content;
}

技術的解説

TypeScript の型定義ファイル(.d.ts)には、グローバル宣言とモジュール宣言の 2 種類があります:

  1. グローバル宣言: import文やexport文がないファイル。プロジェクト全体で自動的に認識される

  2. モジュール宣言: import文やexport文があるファイル。モジュールとして扱われ、明示的にインポートする必要がある

SVG ファイルのような特殊なファイル形式に対する型定義は、一般的にグローバル宣言として提供されます。しかし、import React from "react"のような文を入れるとモジュール宣言になってしまうため、今回のエラーが発生しました。

そこで今回使用したのがimport()構文です。通常の import 文と異なり、この構文は型定義の中で他のモジュールの型を参照するために使用でき、ファイルのグローバル宣言としての性質を維持できます

これによって、@svgr/webpackの型定義がグローバルに適用され、SVG モジュールの型解決ができるようになりました。

おまけ

先輩の指摘で判明しましたが、今回の場合このように書けば解決できました。

declare module "*.svg" {
  import type { FC, SVGProps } from "react";
  const content: FC<SVGProps<SVGElement>>;
  export default content;
}

React だと認識されないけど、個別インポートだと認識されるみたいですね。
ふーんやるじゃん。

 
 
 
 
以上です。

KA projects

Discussion