Friday, September 8, 2023

One extra step after configuring @svgr/webpack in TypeScript projects

SVGR
TypeScript
React

 views

Cover photo for One extra step after configuring @svgr/webpack in TypeScript projects

Problem

You may have followed the steps in the documentation and thought you were done setting @svgr/webpack. But when you try to import an SVG file, you may encounter the following error.

Cannot find module 'path/to/file.svg' or its corresponding type declarations.

Or if you are doing so in a Next.js project, you may find that the imported component is in any type.

Cause

This is because TypeScript has no idea what the type *.svg should become when it is imported into TS files. It is never being instructed or informed. And this is exactly what we are going to do.

Solution

  1. Create a declaration file. It can be in any name and in any folder, but for the sake of this example, let's name it src/types/image.d.ts.

  2. Declare the type of the import.

    image.d.ts
    // instruct TS that, when we do
    // import Svg from './assets/file.svg'
    // Svg should be in FC<SVGProps<SVGSVGElement>> type
    // i.e. an SVG component
    declare module '*.svg' {
      import { FC, SVGProps } from 'react';
     
      const content: FC<SVGProps<SVGSVGElement>>;        
      export default content;
    }
     
    // instruct TS that, when we do
    // import svg from './assets/file.svg?url'
    // svg should be in string type
    declare module '*.svg?url' {
      const content: string;
      export default content;
    }

    If you are doing this in a Next.js project, change the 2nd declare module statement to the following.

    image.d.ts
    declare module '*.svg?url' {
      import { StaticImageData } from 'next/image';
     
      const content: StaticImageData;
      export default content;
    }

    This is because Next.js has a different way of handling static images, which we are not going to cover in details here.

  3. Instruct TypeScript to include image.d.ts when compiling

    tsconfig.json
    {
      "include": [
        // we use a wildcard here, 
        // but you can add src/types/image.d.ts instead if you prefer
        "src/types/*.d.ts"
      ]
    }

    If you are doing so in a Next.js project, make sure the added statement goes BEFORE next-env.d.ts. This is because Next.js by default declared that importing from *.svg should return any. We need to make sure our declaration overrides Next.js'.

    tsconfig.json
    {
      "include": [
        "src/types/*.d.ts",
        "next-env.d.ts",
      ]
    }

Written By

Matthew Kwong

Matthew Kwong

Senior Web Engineer @ Viu