已通过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
相关产品推荐
相关产品推荐

