AngryBoy
AngryBoy

Reputation: 5153

Unable to import svg files in typescript

In typescript(*.tsx) files I cannot import svg file with this statement:

import logo from './logo.svg';

Transpiler says:[ts] cannot find module './logo.svg'. My svg file is just <svg>...</svg>.

But in .js file I'm able to import it without any issues with exact the same import statement. I suppose it has something to do with type of svg file which must be set somehow for ts transpiler.

Could you please share how to make this work in ts files?

Upvotes: 413

Views: 433832

Answers (28)

Breno Melo
Breno Melo

Reputation: 31

    // eslint-disable-next-line spaced-comment
/// <reference types="react-scripts" />

If you are using the eslint plugin it maybe because that you have deleted it, thinking it was a comment but not to read the svg you need this type script module just disable the line and be happy

Upvotes: 3

Abdulrahman Khlefat
Abdulrahman Khlefat

Reputation: 36

This worked for me:

import Logo from './folder.svg?react';

<Folder width={10} height={10} />

a part of the solution was to remove import {ReactComponent as Folder}

Upvotes: 0

Aliaz
Aliaz

Reputation: 11

If you are using Next.js and encountering this error in the CI/CD pipeline but not locally, don't panic. Simply add next-env.d.ts to your git repository. If desired, you can remove the file before building the application in the Dockerfile.

Upvotes: 0

Zohaib Amir
Zohaib Amir

Reputation: 539

I faced this same issue in expo here is my solution

import { ImageSourcePropType } from "react-native";

declare module "*.png" {
  const value: ImageSourcePropType | string;
  export default value;
}

declare module "*.svg" {
  const value: ImageSourcePropType | string;
  export default value;
}

Upvotes: 0

VladStepu2001
VladStepu2001

Reputation: 163

Here's the proper "svg.d.ts" file for Vue.js that will fix the error and also make it recognize the imported SVG as an actual <svg> element:

declare module '*.svg' {
  import type { SVGAttributes, DefineComponent } from 'vue';

  const content: DefineComponent<SVGAttributes>;
  export default content;
}

Upvotes: 1

ishandutta2007
ishandutta2007

Reputation: 18284

If you are using esbuild like me, you have to add loader to esbuild.build params:

import esbuild from 'esbuild'
await esbuild.build({
  loader: {
    '.svg': 'dataurl',
  },
})

Upvotes: 0

Kiran Mohan
Kiran Mohan

Reputation: 3016

I had the same issue while trying out a REACT + typescript tutorial.
What worked for me was the following import statement.

import * as logo from 'logo.svg'

Here are my dependencies in package.json.

  "dependencies": {
    "react": "^16.8.4",
    "react-dom": "^16.8.4",
    "react-scripts-ts": "3.1.0"
  },
  "devDependencies": {
    "webpack": "^4.0.0"
  }

Hope it helps someone.

Upvotes: 5

Vishal Parmar
Vishal Parmar

Reputation: 21

for me in react native "0.72.6",

Create an ./globals.d.ts file in the root of your project, at the same place/level your ./tsconfig.json is.

add this lines in globals.d.ts,

declare module '*.svg' {
  const content: string;
  export default content;
}

don't include in ./tsconfig.json

Use:

import SVG_google from '.SVG_google.svg';

Upvotes: 2

Ronan-Yann Lorin
Ronan-Yann Lorin

Reputation: 339

If you use vite, adding the following compilerOptions to tsconfig.json fixed the error for me:

  "compilerOptions": {
    "types": ["vite/client", "node"],

Upvotes: 21

Sumit Wadhwa
Sumit Wadhwa

Reputation: 3227

If you're using NextJs ^13 with TypeScript, this should help you out:

npm install --save-dev @svgr/webpack

Since NextJs uses webpack, we need this plugin to process svg files and use those file import as React components. Learn more about svgr webpack plugin.

Then, open your next.config.* file, and add this webpack config to next config:

module.export = {
 // other config values

 webpack(config) {
   config.module.rules.push({
     test: /\.svg$/i,
     issuer: { and: [/\.(js|ts|md)x?$/] },
     use: ['@svgr/webpack'],
   });
   return config;
  }
};

Now, we need to override type definition for svg file content. It shouldn't be any but a proper component definition.

Create a custom .d.ts file anywhere in your project with the following content:

// custom.d.ts
declare module '*.svg' {
  const ReactComponent: React.FC<React.SVGProps<SVGSVGElement>>;
  export default ReactComponent;
}

We also need to import this file in typescript config file - tsconfig.json:

"include": [
 "types/custom.d.ts",
 "next-env.d.ts"
]

Our custom declaration file should be included before next-env.d.ts. This order is important.

We should be good now.

import SvgLogo from 'path/to/logo.svg';

function App() {
   return (
      <SvgLogo />
   );
}

Upvotes: 2

Emad Armoun
Emad Armoun

Reputation: 2087

Import an SVG file in a CRA app

If you want to import an SVG file in a CRA app (create-react-app), without doing any config, you can use these methods:

TypeScript Files

import myIconFileName from './assets/images/my-icon.svg';
...    
<img src={myIconFileName} />

JS Files

import { ReactComponent as MyIcon } from "./assets/images/my-icon.svg";
...
<MyIcon />

Upvotes: -5

Cole nelson
Cole nelson

Reputation: 194

This comment helped if you want src functionality as well as being able to make it a react component. https://github.com/parcel-bundler/parcel/discussions/7910#discussioncomment-3690319

This goes in your globals.d.ts at the same level as your tsconfig.json

declare module '*.svg' {
export const ReactComponent: React.FC<React.SVGProps<SVGSVGElement>>;
const src: string;
export default src;

}

Upvotes: 5

Alex Medveshchek
Alex Medveshchek

Reputation: 685

If you're using Webpack >= v5 and would like to inline your image, this would perfectly work for you:

const logo = require('./logo.svg') as string;

function MyComponent() {
  return (
    <img src={logo} />  // <img src="data:image/svg+xml;base64,..." />
  );
}

In webpack.config.js add the following changes:

module: {
  rules: [
    // inline svg-files (see https://webpack.js.org/guides/asset-modules/)
    {
      test: /\.svg/,
      type: 'asset/inline'
    }
  ]
}

And yeah, also please note it might not work if your Content-Security-Policy header is set to strict options (e.g. only 'self') so it wouldn't allow inline images.

In that case you'll see a "broken" image on the web-page and a warning in the Dev Tools Console. To fix, just add data: into Content-Security-Policy setup, like this:

Content-Security-Policy: img-src 'self' data:

Upvotes: 0

Coding Techniques
Coding Techniques

Reputation: 169

Cannot find a module or its corresponding type declarations | Unable to import svg files in typescript

  1. Inside that ./custom.d.ts file, add this:
declare module '*.svg' {
  const content: string;
  export default content;
}

Upvotes: 17

Rax Weber
Rax Weber

Reputation: 3780

If none of the other answers work, try to restart your IDE (i.e. VS Code). In my case, that fixed it.

Upvotes: 3

Graham
Graham

Reputation: 14153

If you use webpack, you can do this by creating a custom types file.

Create a file named custom.d.ts with the following content:

declare module "*.svg" {
  const content: React.FunctionComponent<React.SVGAttributes<SVGElement>>;
  export default content;
}

Add the custom.d.ts to tsconfig.json as below

"include": ["src/components", "src/custom.d.ts"]

Source: https://webpack.js.org/guides/typescript/#importing-other-assets

Upvotes: 625

Robert
Robert

Reputation: 20286

For me it worked when I put the following line in src/types/images.d.ts

declare module '*.svg';

and I'm importing images the following way

import { ReactComponent as WifiIcon } from '../../../assets/images/Wifi.svg';

in tsconfig.json

I have following complierOptions

"compilerOptions": {
    "typeRoots": ["node_modules/@types", "src/types"]
}

hope it helps someone. I use CRA the newest version.

Upvotes: 1

Hamidreza Soltani
Hamidreza Soltani

Reputation: 624

Solution without webpack and custom.d.ts

For me, none of the above solutions worked alone. Because I don't use the Webpack in my current project.

I investigated the outputs in the log, then the following way worked for me, without creating a file (custom.d.ts), changing the config, or installing a new dependency:

const logo: string = require("../assets/images/logo.svg").default;

<img src={logo} alt="logo" />

For svg format you need to add .default, but not for png format.

Upvotes: 16

John Datserakis
John Datserakis

Reputation: 970

I scoured the internet looking for a solution to this issue. This stackoverflow question came up as the top lead, but none of the answers worked for me.

Finally, I was able to come to a solution by trying a few different techniques.

  1. Create an ./globals.d.ts file in the root of your project, at the same place/level your ./tsconfig.json is.

  2. Inside that ./globals.d.ts file, add this:

declare module '*.svg' {
  const content: string;
  export default content;
}

This properly imports the .svg as a string, which is an issue I noticed in the top-rated answer.

  1. Update your tsconfig.json with the following:
{
  "files": ["globals.d.ts"]
}

That's it - that got it to work in my case. I will note - this is in a VanillaJS app.

Upvotes: 57

Josh M.
Josh M.

Reputation: 27831

For me, I had to include react-app-env.d.ts in my tsconfig*.json:

  "include": [
    "src/Router.tsx",        // my main entry point
    "src/global.d.ts",       // global stuff
    "src/react-app-env.d.ts" // react global stuff
  ]

Upvotes: 1

Sidney Liu
Sidney Liu

Reputation: 487

If you use webpack, install svg-inline-loader, add the module in the webpack.config.js:

{
    test: /\.svg$/,
    loader: 'svg-inline-loader',
}

It works well after building.

If your IDE reports an interactively error, it can solved by adding //@ts-ignore:

//@ts-ignore
import logo from './logo.svg';

svg-inline-loader webpack docs

Upvotes: -1

Allenaz
Allenaz

Reputation: 1109

  • If you're using create-react-app 2+: docs

Add a custom.d.ts file (I created it on the root path of my src dir) with the correct type (thanks to RedMatt):

declare module '*.svg' {
  const content: React.FunctionComponent<React.SVGAttributes<SVGElement>>;
  export default content;
}

Install svg-react-loader or some other, then:

  • Use it as the main svg loader
  • Or if you're migrating a codebase and don't want to touch the working part (JS) specify the loader on the import:
import MySVG from '-!svg-react-loader!src/assets/images/name.svg'

Then just use it as a JSX tag:

function f() { 
  return (<MySVG />); 
}

Upvotes: 70

Premji
Premji

Reputation: 87

Hope! This will help someone.

Actually, I tried all the steps but one thing we have to understand, you have to create the custom.d.ts file into the corresponding SVG import folder.

ts config file

{
  "compilerOptions": {
    "target": "ES6",
    "jsx": "react",
    "module": "ESNext",
    "moduleResolution": "Node",
    "baseUrl": "./",
    "paths": {
      "@components/*": ["src/components/*"],
      "@styles/*": ["src/styles/*"],
      "@static/*": ["src/static/*"]
    },
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "isolatedModules": true
  },
  "include": ["src/**/*", "src/static/optional.d.ts"],
  "exclude": ["node_modules", "build"]
}

optional.d.ts

declare module '*.svg' {
    import * as React from 'react';

    export const ReactComponent: React.FunctionComponent<React.SVGProps<
        SVGSVGElement
    > & { title?: string }>;

    const src: string;
    export default src;
}

Finally the common export file:

import Logo from './images/logo.svg';
import BellDot from './images/bell-dot.svg';
import Logout from './images/logout.svg';
import pageNotFound from './images/page-not-found.png';

export {
    Logo,
    BellDot,
    pageNotFound,
    Logout
}

For a better idea:

enter image description here

Upvotes: 6

Oleksandr Danylchenko
Oleksandr Danylchenko

Reputation: 699

If you're using the Create-React-App starter, make sure that the react-app-env.d.ts contains the line:

/// <reference types="react-scripts" />

Upvotes: 12

kimbaudi
kimbaudi

Reputation: 15615

You can declare module for svgs the same way as create-react-app:

react-app.d.ts

declare module '*.svg' {
  import * as React from 'react';

  export const ReactComponent: React.FunctionComponent<React.SVGProps<
    SVGSVGElement
  > & { title?: string }>;

  const src: string;
  export default src;
}

see source

Upvotes: 24

jilvanx
jilvanx

Reputation: 461

The solution that I found: In ReactJS project, in file react-app-env.d.ts you just remove the space in the comment such as:

Before

// / <reference types="react-scripts" />

After

/// <reference types="react-scripts" />

I hope to help you

Upvotes: 32

endymion1818
endymion1818

Reputation: 485

There's an alternative way of doing this which we've implemented: make your SVGs components. I did this because it bugged me that I was using commonJS require statements alongside my imports.

Upvotes: 4

AngryBoy
AngryBoy

Reputation: 5153

Thanks smarx for pointing out use require(). So in my case it should be:

const logo = require("./logo.svg") as string;

which works fine in *.tsx files

Upvotes: 86

Related Questions