React/Typescript无法将svg文件作为组件导入

6

当我在React/Typescript/Webpack 5项目中导入svg时,出现了以下错误:

Cannot find module '../path' or its corresponding type declarations.

然后我添加了:

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

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

    const src: string;
    export default src;
}

将SVG作为ReactElement使用时需要在custom.d.ts文件中添加类型声明。如果将SVG作为src图像使用,则可以正常工作。但是,如果需要根据用户点击更改其内容,则需要将SVG作为ReactElement使用。尝试导入SVG时,可能需要使用以下语法:
import DislikeIcon from '../../media/icons/dislike.svg';

const Component = () => (<> <DislikeIcon /> </>)

之后我遇到了这个错误:

<data:image/svg... /> 的大小写使用不正确。在 React 组件中应该使用 PascalCase,而在 HTML 元素中应该使用小写。

之后我尝试了:

import { ReactComponent as DislikeIcon } from '../../media/icons/dislike.svg';

并得到:

警告:React.jsx: 类型无效 -- 预期为字符串(内置组件)或类/函数(复合组件),但却得到了undefined。您可能忘记从定义文件中导出组件,或者您可能混淆了默认导入和命名导入。

我的webpack.config.js文件

module.exports = {
    ...
    module: {
        rules: [
            {
                test: /\.[jt]sx?$/,
                use: ['babel-loader'],
                exclude: /node_modules/,
            },
            {
                test: /\.scss$/,
                exclude: /node_modules/,
                use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader'],
            },
            {
                test: /\.svg$/,
                loader: 'url-loader',
            },
            {
                test: /\.(?:ico|gif|png|jpg|jpeg)$/i,
                type: 'asset/resource',
            },
            {
                test: /\.(woff(2)?|eot|ttf|otf)$/,
                type: 'asset/inline',
            },
        ],
    },
    ...
};

我的 custom.d.ts 文件:

declare module '*.png' {
    const value: string;
    export = value;
}
declare module '*.jpg' {
    const value: string;
    export = value;
}
declare module '*.svg' {
    import * as React from 'react';

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

    const src: string;
    export default src;
}

我的tsconfig.json文件:
{
    "compilerOptions": {
      "target": "ES5",
      "module": "ESNext",
      "moduleResolution": "node",
      "lib": [
        "DOM",
        "ESNext"
      ],
      "jsx": "react-jsx",
      "noEmit": true,
      "isolatedModules": true,
      "esModuleInterop": true,
      "strict": true,
      "skipLibCheck": true,
      "forceConsistentCasingInFileNames": true,
      "resolveJsonModule": true,
      "allowJs": true,
      "checkJs": true,
    },
    "include": ["src/**/*", "./custom.d.ts"],
    "exclude": ["node_modules", "build"],
  }

我为这个问题搜索了很多答案,但每个人都说类似的话。这让我花费了我没有的时间。有人有任何建议吗?

谢谢您的关注!

1个回答

0
我在这里找到了解决方案:https://duncanleung.com/typescript-module-declearation-svg-img-assets/。感谢(Duncan Leung)。
解决方案是创建一个 ./src/@types/assets/index.d.ts TypeScript 模块声明文件来管理媒体资源。
关于 TypeScript 模块声明文件的一个重要注意点在于如何使用 typeRoots 属性将它们包含在 tsconfig.json 中。
属性 typeRoots 定义类型声明所包含的 types 文件夹,但是每个子文件夹必须包含一个 index.d.ts 模块声明文件,因为 typeRoots 下的每个子文件夹都被视为“包”并添加到您的项目中。
我们错误地尝试将 .svg 模块声明放在 ./src/@types/index.d.ts 下。
将 .svg 文件的 index.d.ts 移动到它自己的 ./src/@types/assets 子文件夹下让 TypeScript 正确识别 .svg 模块声明。
./src/@types/assets/index.d.ts
declare module "\*.svg" {
  import React = require("react");
  export const ReactComponent: React.SFC<React.SVGProps<SVGSVGElement>>;
  const src: string;
  export default src;
}

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

这是一个tsconfig.json的示例:

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"]
}

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