Question
In TypeScript (.tsx) files, importing an SVG like this causes an error:
import logo from './logo.svg';
The TypeScript compiler reports:
[ts] Cannot find module './logo.svg'.
The SVG file itself is a normal SVG file:
<svg>...</svg>
The same import works in a .js file without any issue using the exact same statement. It seems like TypeScript may need to know the type of .svg files before allowing the import.
How can SVG imports be made to work correctly in TypeScript or TSX files?
Short Answer
By the end of this page, you will understand why TypeScript rejects SVG imports, why JavaScript often allows them, and how to fix the problem using module declarations. You will also see common SVG import patterns used in React and TypeScript projects.
Concept
TypeScript checks types at compile time. When you write:
import logo from './logo.svg';
TypeScript tries to answer a question before your app runs: what type does ./logo.svg export?
For JavaScript files, many bundlers such as Webpack, Vite, or Parcel already know how to handle image and SVG imports during the build. JavaScript does not care about static types, so the import can work at runtime.
TypeScript is stricter. It does not automatically know what a .svg file exports unless you tell it. As far as TypeScript is concerned, .svg is not a built-in module type like .ts or .js.
That is why you often need a module declaration such as:
declare module '*.svg' {
const src: string;
export default src;
}
This tells TypeScript:
- any import ending in
.svgis a valid module - the default export is a
string
Mental Model
Think of TypeScript as a security guard checking badges at a building entrance.
- A
.tsfile has a badge TypeScript recognizes. - A
.jsfile often gets through because runtime tooling handles it later. - A
.svgfile shows up with no badge TypeScript understands.
So TypeScript stops it and says: "I don't know what this module is."
A declaration file is like giving all .svg files an approved badge. Once you add that badge, TypeScript allows them in.
Syntax and Examples
The most common fix is to add a declaration file.
1. Importing SVG as a file path string
Create a file such as src/types/images.d.ts or src/custom.d.ts:
declare module '*.svg' {
const src: string;
export default src;
}
Then this works:
import logo from './logo.svg';
export default function Header() {
return <img src={logo} alt="Site logo" />;
}
Why this works
The declaration tells TypeScript that logo is a string, usually a URL produced by your bundler.
2. Importing SVG as a React component
Some toolchains support syntax like this:
Step by Step Execution
Consider this example:
// src/custom.d.ts
declare module '*.svg' {
const src: string;
export default src;
}
// src/App.tsx
import logo from './logo.svg';
export default function App() {
return <img src={logo} alt="Logo" />;
}
Here is what happens step by step:
-
TypeScript reads
App.tsx. -
It sees
import logo from './logo.svg'. -
Without help, it does not know what
.svgmeans as a module. -
It scans declaration files included in the project.
-
It finds:
Real World Use Cases
SVG imports are common in real applications.
Brand assets
import companyLogo from './assets/company-logo.svg';
<img src={companyLogo} alt="Company logo" />
Used in:
- headers
- authentication pages
- dashboards
Icon systems
import searchIcon from './icons/search.svg';
<button>
<img src={searchIcon} alt="Search" />
</button>
Used in:
- buttons
- menus
- action bars
Inline SVG as components
import { ReactComponent as WarningIcon } from './warning.svg';
Real Codebase Usage
In real projects, developers usually combine SVG declarations with a few practical patterns.
Centralized asset declarations
Instead of defining only .svg, teams often declare multiple asset types in one place:
declare module '*.svg' {
const src: string;
export default src;
}
declare module '*.png' {
const src: string;
export default src;
}
declare module '*.jpg' {
const src: string;
export default src;
}
This avoids repeated import errors for static assets.
Choosing one import style
Teams usually standardize on one of these:
- SVG as URL string for simple images
- SVG as React component for icons and styled graphics
That keeps code consistent.
Guarding against bundler mismatch
A declaration only satisfies TypeScript. Your build tool must also support the import style.
Common Mistakes
1. Adding the declaration file outside TypeScript's included paths
Broken setup:
{
"include": ["src"]
}
If your declaration file is outside src, TypeScript may never see it.
How to avoid it:
- place the
.d.tsfile inside an included folder - or update
tsconfig.json
2. Writing the wrong module shape
Broken declaration:
declare module '*.svg' {
export default React.Component;
}
This is not a valid way to describe the module.
Use a proper declaration instead:
declare module '*.svg' {
const src: string;
export src;
}
Comparisons
| Import style | What you get | Common usage | Type declaration |
|---|---|---|---|
import logo from './logo.svg' | A string URL or asset path | <img src={logo} /> | const src: string; export default src; |
import { ReactComponent as Logo } from './logo.svg' | A React component | <Logo /> | export const ReactComponent: React.FunctionComponent<...> |
| JavaScript | TypeScript |
|---|---|
| Bundler may allow SVG import without extra work | TypeScript needs to know the module type |
| No static type checking for imported assets |
Cheat Sheet
Import SVG as a string
declare module '*.svg' {
const src: string;
export default src;
}
import logo from './logo.svg';
<img src={logo} alt="Logo" />
Import SVG as a React component
declare module '*.svg' {
import * as React from 'react';
export const ReactComponent: React.FunctionComponent<
React.SVGProps<SVGSVGElement>
>;
const src: string;
export default src;
}
FAQ
Why does SVG import work in JavaScript but not TypeScript?
JavaScript does not do static type checking. TypeScript does, so it needs a declaration telling it what a .svg module exports.
Where should I put the *.d.ts file?
Place it inside a folder included by tsconfig.json, commonly inside src.
Should an imported SVG be typed as string or as a React component?
It depends on your setup. Use string when the SVG is imported as a file path. Use a React component type when your toolchain supports component-style SVG imports.
Is a module declaration enough to make SVG imports work?
Not always. It fixes TypeScript type errors, but your bundler must also know how to load SVG files.
Do I need to change tsconfig.json?
Only if TypeScript is not picking up your declaration file. Usually making sure the file is inside an included path is enough.
Can I declare multiple asset types the same way?
Yes. Many projects add declarations for .png, .jpg, .svg, and similar asset files.
Why is the error still visible after adding the declaration?
Your editor may need a TypeScript server restart, or the declaration file may be outside the included project paths.
Mini Project
Description
Build a small React + TypeScript header component that displays a logo imported from an SVG file. This project demonstrates how to teach TypeScript what .svg imports mean and then use the imported asset safely inside TSX.
Goal
Create a working TSX component that imports an SVG file without TypeScript errors and renders it in the UI.
Requirements
- Create a TypeScript declaration file for
.svgmodules. - Import an SVG file into a TSX component.
- Render the imported SVG using an
<img>element. - Ensure the declaration file is placed where TypeScript can find it.
Keep learning
Related questions
@Directive vs @Component in Angular: Differences, Use Cases, and When to Use Each
Learn the difference between @Directive and @Component in Angular, including use cases, examples, and when to choose each.
Angular (change) vs (ngModelChange): What’s the Difference?
Learn the difference between Angular (change) and (ngModelChange), when each fires, and which one to use in forms and inputs.
Angular @ViewChild Returning Undefined: Lifecycle, Child Components, and Fixes
Learn why Angular @ViewChild can be undefined, when it becomes available, and how to access child components correctly using lifecycle hooks.