In typescript, is there a way to resolve asset (pngs,svgs...etc) files that require declarations and keep path validation?
The Problem
- With a relative path import the Spinner.svg will show multiple definitions but resolve the declaration over navigating you to the file. No path validation for typos or level
- With a path alias using
pathsin tsconfig.json, it will not resolve any files and only show the declaration file with the .svg definitions. - Invalid imports silently pass.
Example with SVG assets in a React Project
file directory structure:
- src
- src/assets.d.ts
- src/assets
- src/assets/Spinner.svg
- src/component/Component.tsx
For typescript to directly import a svg|png|jpg or other asset unsupported assets, you have to write a custom declaration file.
Example with react + react-native-svg
declare module '*.svg' {
const content: React.FC<React.SVGAttributes<SVGElement>>
export default content
}
tsconfig.json file with assets as a path alias.
{
"compilerOptions": {
"esModuleInterop": true,
"isolatedModules": true,
"jsx": "react",
"lib": ["ES2023"],
"moduleResolution": "node",
"noEmit": true,
"strict": true,
"strictNullChecks": true,
"resolveJsonModule": true,
"target": "esnext",
"baseUrl": "./",
"paths": {
"assets/*": ["src/assets/*"]
}
},
"include": ["src/**/*"],
"exclude": [
"node_modules",
"babel.config.js",
"metro.config.js",
"jest.config.js"
]
}
Example typescript imports in Component.tsx
// opens a definitions window and shows both the relative path import and declaration file
import ../assets/Spinner.svg
// Only resolve the assets.d.ts file
import assets/Spinner.svg
// bad imports that do not error (until runtime)
import ../assets/Spinner1.svg
import ../assets/123/Spinner.svg
Hoping for the following solution(s):
- Path validation works and redirects the IDE to the asset implementation file (IE the file with the actual asset data).
- VSCode (and other IDEs) can validate that the path is valid.
- Works in CI so those paths can be validated to exist.
The solution does not need to be scoped directly towards tsconfig.json or declarations but that would be optimal.
Alternatives
- Use a scoped path and only resolve .svg from that scoped path.
- prevents path level import issues
- still has potential to fail with typos in a filename.
Example declaration
declare module 'assets/*.svg' {
const content: React.FC<React.SVGAttributes<SVGElement>>
export default content
}
- Create / Add a plugin that resolves paths in IDE
- Something like eslint-plugin-validate-declared-imports