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

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. 方案1中,React.HTMLProps包含已废弃的字符串类型ref,而styled-components组件仅接受函数/对象类型的ref,导致类型不兼容。
  2. 方案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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 03:37:29