无法在TypeScript中导入SVG文件

377
在typescript(*.tsx)文件中,我无法使用以下语句导入svg文件:
import logo from './logo.svg';

转译器显示:[ts] 找不到模块"./logo.svg"。 我的svg文件只是<svg>...</svg>

但在.js文件中,我可以使用完全相同的导入语句轻松导入它,没有任何问题。我认为这与必须以某种方式设置ts转译器的svg文件类型有关。

请问如何使此功能在ts文件中正常工作?


2
SVG文件不是JavaScript,不能像JavaScript模块一样使用。您应该使用HTTP请求加载这些文件。 - toskv
2
你在使用Webpack吗?这是我见过唯一能理解这种import语句的工具。也许是Webpack在你的JavaScript文件中实现了这个功能,但在TypeScript文件中却没有做同样的魔法。(我认为TypeScript本身并不知道该怎么处理这里的代码。) - user94559
2
如果您正在使用Webpack,您可能需要共享您的Webpack配置以获得更多帮助。 - user94559
4
通读一下,你可能可以执行const logo = require("./logo.svg");或者直接忽略这个错误。(我相信TypeScript仍然会输出正确的代码。) - user94559
7
为什么Webpack/React要把事情搞得这么复杂?难道用import导入不是更简单吗?对于像我这样的新手来说,这些东西让我感到沮丧。我们不是已经进入了2020年,自动配置应该成为常态了吗? - SimpleGuy
显示剩余3条评论
24个回答

573

如果你使用webpack,可以通过创建一个自定义的类型文件来实现这一点。

创建一个名为custom.d.ts的文件,其内容如下:

declare module "*.svg" {
  const content: React.FunctionComponent<React.SVGAttributes<SVGElement>>;
  export default content;
}
custom.d.ts 添加到 tsconfig.json 中,如下所示。
"include": ["src/components", "src/custom.d.ts"]

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


55
很可能,您需要将其添加到 tsconfig.jsoninclude 部分中。 - Frederik Krautwald
21
谢谢!我知道它一定包含在某个地方,但我不知道在哪里。我甚至认为它可能在tsconfig.json中,但我不知道如何做。感谢您的评论。我进行了搜索并找到了:"files": [ "custom.d.ts" ] - Shil Nevado
15
您可以通过键入以下内容来为 JSX 组件获取类型检查:const content: React.FunctionComponent<React.SVGAttributes<SVGElement>>; - RedMatt
6
custom.d.ts文件能否在全局范围内工作,以便SVG可以放置在不同于custom.d.ts文件的目录中?除非两者在同一目录中,否则会出现"无法找到模块"的错误。 - Nic Scozzaro
3
直到我将*.d.ts的名称更改为确切的"custom.d.ts"之前,该解决方案对我原本*不起作用。请确保这是名称! - Shane Sepac
显示剩余5条评论

82

感谢smarx指出使用require()。所以在我的情况下应该是:

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

在 *.tsx 文件中可以正常工作


17
“logo”可能更适合被命名为“logoPath”,因为它会变成路径。 - DharmaTurtle
3
我认为这是可以争议的。而且,由于问题中使用了“logo”一词,因此将其作为答案更为合适。请注意,我的翻译不影响原意,同时让内容更加易懂。 - ArneHugo
2
@DharmaTurtle,老实说,变量的名称并不是重点,为什么要在这种琐事上分心呢? - ELI7VH
1
无法使其正常工作 - 请澄清? https://stackoverflow.com/questions/65205211/how-to-use-loaded-svg-module - Bondolin
1
这将返回一个 @typescript-eslint/no-var-requires。 - Braian Mellor
显示剩余2条评论

68
  • 如果您使用的是create-react-app 2+文档

在正确的类型中添加一个custom.d.ts文件(我在我的src目录的根路径上创建了它),感谢RedMatt

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

安装svg-react-loader或其他适用的,然后:

  • 将其用作主SVG加载器
  • 或者如果您正在迁移代码库并且不想触及工作部分(JS),请在导入中指定加载器:
import MySVG from '-!svg-react-loader!src/assets/images/name.svg'

然后只需将其用作JSX标记:

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

2
ESLint: 在“-!svg-react-loader!src/assets/svg/bg.svg”中出现意外的“!”符号。不要使用导入语法来配置webpack加载器。(import/no-webpack-loader-syntax) - Terchila Marian
如果您正在使用NextJs,则此解决方案可能不适用于您。请看这里 - Sumit Wadhwa

39

我在互联网上搜索解决这个问题的方案。这个stackoverflow问题是最高的,但是没有一个答案适用于我。

最终,通过尝试几种不同的技术,我成功地找到了解决方案。

  1. 在项目的根目录下,与./tsconfig.json同一级别的位置中创建一个./globals.d.ts文件。

  2. ./globals.d.ts文件中添加以下内容:

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

这样可以将.svg文件正确地导入为字符串,这是我在排名第一的答案中注意到的问题。

  1. 更新你的tsconfig.json文件如下:
{
  "files": ["globals.d.ts"]
}

就是这样 - 在我的情况下,这样做使它能够运行。我要注意的是 - 这是在一个纯JS应用程序中。


29

我找到的解决方案:在 ReactJS 项目中的 react-app-env.d.ts 文件中,只需删除注释中的空格,例如:

改变前:

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

之后

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

我希望能帮助你


3
对于使用create-react-app并配置了eslint的人来说,这可能会解决问题。 - Daniel Chin
我还没有找到任何解释,但在我的情况下似乎可以工作。有什么想法为什么? - Stamatis Deliyannis
以下是它的解释:https://dev59.com/lVIH5IYBdhLWcg3wMapg#61487071 - Marcel Kalveram
如果你使用 CRA 并配置了 eslint 或其他工具(在我的情况下是 vscode format)来格式化 react-app-env.d.ts 文件,那么你可能会遇到这个问题。它会因为空格注释规则而将 /// 更改为 // /。你可以将其改回来并添加忽略 (/* eslint-disable spaced-comment */),然后问题就解决了。 - David

21

您可以像create-react-app一样声明SVG模块:

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;
}

查看 源代码


我不明白。为什么它定义了 export const ReactComponent 然后使用 export default src?难道不应该是 export default ReactComponent 吗? - vhflat
因为CRA在底层使用了SVGR加载器,它就是这样做的:https://www.npmjs.com/package/@svgr/webpack另请参阅https://github.com/gregberge/svgr/issues/546 - oligofren
只需使用 export const ReactComponent = ...,就可以为我工作,谢谢。 - David Rearte

16
无法找到模块或其相应的类型声明 | TypeScript中无法导入SVG文件
  1. 在./custom.d.ts文件中添加以下内容:
declare module '*.svg' {
  const content: string;
  export default content;
}

15

无需使用webpack和custom.d.ts文件的解决方案

对于我而言,上述所有解决方案都不能单独解决我的问题,因为我当前的项目中没有使用Webpack。

通过查看日志输出,我找到了下面的方法可以解决我的问题,它不需要创建文件(custom.d.ts)、修改配置或者安装新依赖:

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

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

对于svg格式,您需要添加.default,但对于png格式不需要。

谢谢,这个对我有用。您能否解释一下为什么我们应该为 .svg 文件添加 .default,但不需要为 .png 文件添加? - Rahul R

11
如果您正在使用Create-React-App入门,确保react-app-env.d.ts文件包含以下内容:
/// <reference types="react-scripts" />

3
这对我很有效。我还想指出,最直接的方法是使用create-react-app和typescript模板,它会为您配置项目并直接支持使用svg。 - Amin Dannak

6
如果您使用 vite,请将以下 compilerOptions 添加到 tsconfig.json 中,这样可以为我解决错误:
  "compilerOptions": {
    "types": ["vite/client", "node"],

我尝试过了,但在 tsconfig.json 中出现了以下错误:无法找到“node”的类型定义文件。该文件在程序中是因为:编译器选项中指定了类型库“node”的入口点。所以我只是从列表中删除了“node”,然后它就可以工作了。谢谢! - George.
我有"vite/client"和"node",对我来说运行正常。 - Shawn Shaw
1
对我来说,不需要使用"node",只需使用"types": ["vite/client"]就可以了。谢谢! - Raul Rene
vite有点奇怪——模板项目可以导入SVG没有问题,但我的大型项目却出现了错误。可能是依赖或配置冲突了吧?不管怎样,@RaulRene的建议解决了这个问题。 - Partly Cloudy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接