You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

已通过attr指定静态src,Styled Component仍要求该属性必填

问题:如何移除Styled Components包装的react-inlinesvg组件的必填src属性?

我基于react-inlinesvg的SVG组件,用styled-components封装了一个基础图标组件,通过.attrs静态指定了src属性——因为不同SVG文件的样式实现不同,所以每个图标都是独立组件。相关代码如下:

import SVG from 'react-inlinesvg';
import { CSSProperties as _CSSProperties } from "react";
import styled, { Interpolation } from "styled-components";

// Remove undefined from CSSProperties, as all these constants are guaranteed to
// exist.
export type RequiredCSSProperties = Required<_CSSProperties>;

// Add a prop that allows for custom CSS to be added to a styled component instance without
// creating a new styled component.
export type WithCSSProp<T={}> = T & { $css?: Interpolation<Omit<T, "$css">> };

export type MenuIconStyleAttributes = {
    $color?: RequiredCSSProperties['stroke'] | null;
    $width?: RequiredCSSProperties['width'];
    $height?: RequiredCSSProperties['height'];
};

export default styled(SVG).attrs<WithCSSProp<MenuIconStyleAttributes>>(
    (props) => ({
        src: '/icons/menu.svg',
        $color: props.$color ?? null,
        $width: props.$width ?? '24px',
        $height: props.$height ?? 'auto',
        $css: props.$css ?? null
    })
)`
    width: ${({$width}) => $width};
    height: ${({$height}) => $height};

    > path {
        stroke: ${({$color, theme}) => $color ?? theme.textColor};
    }

    ${({$css}) => $css}
`;

使用该组件时,即便已经通过.attrs指定了静态src值,TypeScript仍将src视为必填项,报错信息如下:

No overload matches this call.
  Overload 1 of 2, '(props: PolymorphicComponentProps<"web", FastOmit<Substitute<Substitute<{ string?: string | number | undefined; stroke?: string | undefined; clipPath?: string | undefined; color?: string | undefined; cursor?: string | number | undefined; ... 481 more ...; uniquifyIDs?: boolean | undefined; }, { ...; }>, WithCSSProp<...>>, never>, void, void, {}, {}>): Element', gave the following error.
    Property 'src' is missing in type '{}' but required in type 'FastOmit<Substitute<FastOmit<Substitute<Substitute<{ string?: string | number | undefined; stroke?: string | undefined; clipPath?: string | undefined; color?: string | undefined; cursor?: string | number | undefined; direction?: string | ... 1 more ... | undefined; ... 480 more ...; uniquifyIDs?: boolean | undefined...'.
  Overload 2 of 2, '(props: FastOmit<Substitute<Substitute<{ string?: string | number | undefined; stroke?: string | undefined; clipPath?: string | undefined; color?: string | undefined; cursor?: string | number | undefined; direction?: string | ... 1 more ... | undefined; ... 480 more ...; uniquifyIDs?: boolean | undefined; }, { ...; }>, WithCSSProp<...>>, never>): ReactNode', gave the following error.
    Property 'src' is missing in type '{}' but required in type 'FastOmit<Substitute<Substitute<{ string?: string | number | undefined; stroke?: string | undefined; clipPath?: string | undefined; color?: string | undefined; cursor?: string | number | undefined; direction?: string | ... 1 more ... | undefined; ... 480 more ...; uniquifyIDs?: boolean | undefined; }, { ...; }>, With...'.

我可以把src设为可选,但这个值实际上会被静态赋值覆盖,所以希望完全移除这个属性,请问是否可行?


解决方案:完全移除src属性是可行的

核心思路是在定义组件对外暴露的Props类型时,排除react-inlinesvg的SVG组件原本的必填src属性,同时确保.attrs中的静态赋值能传递给原始组件。

修改后的代码

import SVG from 'react-inlinesvg';
import { CSSProperties as _CSSProperties } from "react";
import styled, { Interpolation } from "styled-components";

// Remove undefined from CSSProperties, as all these constants are guaranteed to exist.
export type RequiredCSSProperties = Required<_CSSProperties>;

// Add a prop that allows for custom CSS to be added to a styled component instance without creating a new styled component.
export type WithCSSProp<T={}> = T & { $css?: Interpolation<Omit<T, "$css">> };

export type MenuIconStyleAttributes = {
    $color?: RequiredCSSProperties['stroke'] | null;
    $width?: RequiredCSSProperties['width'];
    $height?: RequiredCSSProperties['height'];
};

// 排除SVG组件的src属性,定义对外暴露的Props类型
type MenuIconProps = WithCSSProp<MenuIconStyleAttributes>;

// 内部Props包含SVG的完整属性(用于传递给原始组件)+ 自定义Props
type InternalProps = React.ComponentProps<typeof SVG> & MenuIconProps;

export default styled(SVG).attrs<InternalProps, MenuIconProps>(
    (props) => ({
        src: '/icons/menu.svg',
        $color: props.$color ?? null,
        $width: props.$width ?? '24px',
        $height: props.$height ?? 'auto',
        $css: props.$css ?? null
    })
)`
    width: ${({$width}) => $width};
    height: ${({$height}) => $height};

    > path {
        stroke: ${({$color, theme}) => $color ?? theme.textColor};
    }

    ${({$css}) => $css}
`;

简化写法

如果不需要单独定义类型别名,也可以直接在.attrs的泛型中排除src:

export default styled(SVG).attrs<Omit<React.ComponentProps<typeof SVG>, 'src'> & WithCSSProp<MenuIconStyleAttributes>>(
    (props) => ({
        src: '/icons/menu.svg',
        $color: props.$color ?? null,
        $width: props.$width ?? '24px',
        $height: props.$height ?? 'auto',
        $css: props.$css ?? null
    })
)`
    width: ${({$width}) => $width};
    height: ${({$height}) => $height};

    > path {
        stroke: ${({$color, theme}) => $color ?? theme.textColor};
    }

    ${({$css}) => $css}
`;

原理说明

  • react-inlinesvg的SVG组件默认将src设为必填项,直接包装后TypeScript会继承这一约束;
  • 通过Omit<React.ComponentProps<typeof SVG>, 'src'>移除对外Props中的src字段,这样用户使用组件时无需传递该属性;
  • .attrs中静态赋值的src会在内部传递给原始SVG组件,满足其必填要求,不会触发校验错误。

内容的提问来源于stack exchange,提问作者Ptolemy2002

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 11:12:04