Importing SVG files as React Components in TypeScript
I was running into an issue importing .svg
files as React Components in a TypeScript project.
When I was importing any *.svg
files, the TypeScript compiler was erroring:
import React from "react";
import { ReactComponent as SVGIcon } from "~/icons/icon.svg"; ^^^^^^^^^^^^^^^^
// React Component code...
Cannot find module '~/icons/icon.svg'.ts(2307)
Create a index.d.ts Module Declaration File
The solution was to create a ./src/@types/assets/index.d.ts
TypeScript module declaration file for media assets.
One main gotcha about TypeScript module declaration files is in how they are included in tsconfig.json
using the typeRoots
property.
The property
typeRoots
defines thetypes
folder where type declarations will be contained, but theindex.d.ts
module declaration files must be in a subfolder since each subfolder undertypeRoots
is considered a "package" and is added to your project.
We were incorrectly trying to place the .svg
module declarations under ./src/@types/index.d.ts
.
Moving the index.d.ts
for .svg
files to it's own ./src/@types/assets
subfolder allowed TypeScript to correctly recognize the .svg
module declarations.
declare module "\*.svg" { import React = require("react"); const ReactComponent: React.FC<React.SVGProps<SVGSVGElement>>; export default ReactComponent;}declare module "\*.jpg" {
const content: string;
export default content;
}
declare module "\*.png" {
const content: string;
export default content;
}
declare module "\*.json" {
const content: string;
export default content;
}
Here is an example tsconfig.json
:
{
"compileOnSave": false,
"compilerOptions": {
"target": "es5",
"module": "esnext",
"types": ["node"],
"moduleResolution": "node",
"esModuleInterop": true,
"typeRoots": ["./src/@types", "./node_modules/@types"], "lib": ["dom", "es2015", "es2017"],
"jsx": "react",
"sourceMap": true,
"strict": true,
"resolveJsonModule": true,
"noUnusedLocals": true,
"noImplicitAny": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true,
"allowSyntheticDefaultImports": true,
"downlevelIteration": true,
"baseUrl": "./",
"paths": {
"~/*": ["src/*"],
"@turn/styled": ["src/styled"]
}
},
"include": ["./src/**/*", "./test-utils/**/*", "./__mocks__/**/*"],
"exclude": ["node_modules"]
}