React+NextJS中如何正确为svg标签内的SVG标记设置TS类型
SvgIcon类型约束实现方案
修正类型定义解决报错
你之前遇到类型报错的核心原因是使用了不存在的ReactSVG类型,React类型包中内置的SVG元素实例类型为ReactSVGElement,直接替换即可实现基础类型约束:
import type { ReactSVGElement, ReactNode } from 'react'; interface SvgIconProps { children: ReactSVGElement | ReactSVGElement[]; strokeWidth?: number; width?: number; height?: number; className?: string; } export const SvgIcon = ({ children, strokeWidth = 1, width = 24, height = 24, className, }: SvgIconProps) => { return ( <svg xmlns="http://www.w3.org/2000/svg" className={className} fill="none" viewBox={`0 0 ${width} ${height}`} stroke="currentColor" strokeWidth={strokeWidth} width={width} height={height} > {children} </svg> ); };
修改后如果传入<div />、普通文本这类非SVG子元素,TypeScript会直接抛出类型错误,符合约束需求。
同步调整ButtonWithIcon类型
将组件中svgMarkup的类型和SvgIcon的children类型保持一致,普通按钮内容继续保留ReactNode类型即可,实现两类子元素的类型区分:
import type { ReactSVGElement, ReactNode } from 'react'; import { SvgIcon } from "../SvgIcon"; interface ButtonWithIconProps { children: ReactNode; onClick: (...args: any[]) => void; side: "left" | "right"; svgMarkup: ReactSVGElement | ReactSVGElement[]; } export const ButtonWithIcon = ({ children, onClick, side, svgMarkup, }: ButtonWithIconProps) => { return ( <button onClick={onClick} className=""> {side === "left" && <SvgIcon>{svgMarkup}</SvgIcon>} {children} {side === "right" && <SvgIcon>{svgMarkup}</SvgIcon>} </button> ); };
注意:如果你需要传入封装好的自定义图标组件(比如
<HomeIcon />),需要给自定义图标组件标注返回值类型为ReactSVGElement,否则类型校验会不通过。如果项目中自定义图标组件较多,可以将类型调整为ReactSVGElement | ReactSVGElement[] | (() => ReactSVGElement)兼容组件传参。
内联SVG vs img元素选型建议
你倾向于用内联SVG的写法完全合理,两种方案的适用场景如下:
- 选择内联SVG:如果图标需要动态修改颜色(比如继承
currentColor随按钮文字变色)、调整描边粗细、响应交互状态样式,内联SVG是最优方案,不需要把SVG文件存放到public目录,直接作为JSX编写即可,打包时也会自动被构建工具处理。 - 选择img元素:仅适合不需要修改内部样式、纯静态展示的装饰类图标,这种场景下img加载的SVG无法通过CSS修改内部的fill、stroke属性,灵活度远低于内联SVG,不适合通用图标组件场景。
内容的提问来源于stack exchange,提问作者seven
相关产品推荐
相关产品推荐

