React+Styled Components扩展<p>组件Props遇TypeScript错误求助
React + Styled-Components 实现继承
<p>属性的文本组件报错解决 问题背景
需要封装一个继承HTML <p> 所有Props的React组件,通过styled-components实现样式定制,但传递剩余Props时出现TypeScript类型错误。
错误方案1
import React from "react"; import "./text.css"; import { styled } from "styled-components"; interface props extends React.HTMLProps<HTMLParagraphElement> { textSize?: number; } const Paragraph = styled.p<{ $textSize: number }>` font-family: "Poppins"; font-size: ${(props) => props.$textSize}; `; export default function Text({ textSize = 14, children, ...props }: props) { return ( <Paragraph {...props} $textSize={textSize}> {children} </Paragraph> ); }
使用方式
<Text textSize={20}>Hello World</Text>
报错信息
TS2769: No overload matches this call. Overload 1 of 2, '(props: { slot?: string | undefined; style?: CSSProperties | undefined; title?: string | undefined; ref?: ((instance: HTMLParagraphElement | null) => void) | RefObject<...> | null | undefined; ... 264 more ...; $textSize: number; } & Partial<...> & { ...; } & { ...; }): ReactElement<...>', gave the following error. Type '{ children: ReactNode; $textSize: number; accept?: string | undefined; acceptCharset?: string | undefined; action?: string | undefined; allowFullScreen?: boolean | undefined; ... 363 more ...; key?: Key | ... 1 more ... | undefined; }' is not assignable to type '{ slot?: string | undefined; style?: CSSProperties | undefined; title?: string | undefined; ref?: ((instance: HTMLParagraphElement | null) => void) | RefObject<...> | null | undefined; ... 264 more ...; $textSize: number; }'. Types of property 'ref' are incompatible. Type 'LegacyRef<HTMLParagraphElement> | undefined' is not assignable to type '((instance: HTMLParagraphElement | null) => void) | RefObject<HTMLParagraphElement> | null | undefined'. Type 'string' is not assignable to type '((instance: HTMLParagraphElement | null) => void) | RefObject<HTMLParagraphElement> | null | undefined'. Overload 2 of 2, '(props: StyledComponentPropsWithAs<"web", string, { $textSize: number; }, never, string>): ReactElement<StyledComponentPropsWithAs<"web", string, { $textSize: number; }, never, string>, string | JSXElementConstructor<...>>', gave the following error. Type '{ children: ReactNode; $textSize: number; accept?: string | undefined; acceptCharset?: string | undefined; action?: string | undefined; allowFullScreen?: boolean | undefined; ... 363 more ...; key?: Key | ... 1 more ... | undefined; }' is not assignable to type 'IntrinsicAttributes & { $textSize: number; } & Partial<{}> & { theme?: DefaultTheme | undefined; } & { as?: string | undefined; forwardedAs?: string | undefined; }'. Property 'children' does not exist on type 'IntrinsicAttributes & { $textSize: number; } & Partial<{}> & { theme?: DefaultTheme | undefined; } & { as?: string | undefined; forwardedAs?: string | undefined; }'. 14 | export default function Text({ textSize = 14, children, ...props }: props) { 15 | return ( > 16 | <Paragraph {...props} $textSize={textSize}> | ^^^^^^^^^ 17 | {children} 18 | </Paragraph> 19 | );
错误方案2
import React from "react"; import "./text.css"; import { styled } from "styled-components"; interface props extends React.HTMLProps<HTMLParagraphElement> { $textSize?: number; } const Paragraph = styled.p<props>` font-family: "Poppins"; font-size: ${(props) => props.$textSize}; color: white; `; export default function Text({ $textSize = 14, children, ...props }: props) { return ( <Paragraph $textSize {...props}> {children} </Paragraph> ); }
报错信息
ERROR in src/globalComponents/Text/index.tsx:17:16 TS2769: No overload matches this call. Overload 1 of 2, '(props: { $textSize?: number | undefined; cite?: string | undefined; data?: string | undefined; form?: string | undefined; label?: string | undefined; slot?: string | undefined; span?: number | undefined; ... 362 more ...; wrap?: string | undefined; } & Partial<...> & { ...; } & { ...; }): ReactElement<...>', gave the following error. Type 'boolean' is not assignable to type 'number'. Overload 2 of 2, '(props: StyledComponentPropsWithAs<"web", string, props, never, string>): ReactElement<StyledComponentPropsWithAs<"web", string, props, never, string>, string | JSXElementConstructor<...>>', gave the following error. Type 'boolean' is not assignable to type 'number'. 15 | export default function Text({ $textSize = 14, children, ...props }: props) { 16 | return ( > 17 | <Paragraph $textSize {...props}> | ^^^^^^^^^ 18 | {children} 19 | </Paragraph> 20 | );
正确解决方案
问题根源
- 方案1中,
React.HTMLProps包含已废弃的字符串类型ref,而styled-components组件仅接受函数/对象类型的ref,导致类型不兼容。 - 方案2中,
$textSize {...props}属于语法错误,且将自定义属性混入原生Props接口会造成类型污染。
正确代码实现
import React from "react"; import { styled } from "styled-components"; // 用ComponentPropsWithoutRef获取<p>的标准Props,排除废弃的字符串ref type TextProps = React.ComponentPropsWithoutRef<"p"> & { textSize?: number; }; // styled组件仅声明自定义样式属性,$前缀是styled-components约定的私有属性标识 const StyledParagraph = styled.p<{ $textSize: number }>` font-family: "Poppins"; // 为font-size添加单位,避免无效样式 font-size: ${props => `${props.$textSize}px`}; `; export default function Text({ textSize = 14, children, ...props }: TextProps) { return ( <StyledParagraph {...props} $textSize={textSize}> {children} </StyledParagraph> ); }
关键改进点
- 替换
React.HTMLProps<HTMLParagraphElement>为React.ComponentPropsWithoutRef<"p">,规避废弃ref类型冲突。 - 分离自定义属性与原生Props,保持类型清晰,符合styled-components的属性命名规范。
- 为
font-size添加单位(如px),确保样式渲染有效。
使用方式
// 同时支持自定义属性和<p>的原生属性 <Text textSize={20} className="custom-class" id="intro">Hello World</Text>
内容的提问来源于stack exchange,提问作者Daniel Murillo
相关产品推荐
相关产品推荐

