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

如何基于styled-system与styled-components创建可匹配层级的通用Heading组件

可自动匹配层级标签的通用Heading组件实现

原有实现的报错根因

  • 动态拼接生成的h${level}标签被TS推断为宽泛的string类型,没有匹配到React内置的合法HTML元素类型映射
  • 原Props定义把as暴露为必传的可选参数,和“根据level自动匹配标签”的设计目标冲突
  • 动态组件没有明确的类型约束,TS无法校验styled-system透传的TextAlign、Color属性是否符合组件接收要求

修正后的实现方案

  1. 收窄类型范围,把动态标签的类型限定在合法的h1-h6区间
  2. 调整组件props定义:把as设为可选的标签覆盖参数,而非强制外部传入的内容
  3. 给动态组件加上明确的React类型标注,消除TS的类型校验报错

完整可运行代码

import css from "@styled-system/css"
import styled from "styled-components"
import { color, ColorProps, textAlign, TextAlignProps, variant } from "styled-system"
import type { ComponentPropsWithoutRef, ElementType } from "react"

// 定义严格的标题层级、对应标签类型
type HeadingLevel = 1 | 2 | 3 | 4 | 5 | 6
type HeadingTag = `h${HeadingLevel}`

// 组件对外暴露的Props类型
type HeadingProps = {
  /** 标题层级,对应自动渲染h1-h6标签 */
  level: HeadingLevel
  /** 可选:手动覆盖渲染的HTML标签,满足特殊场景使用需求 */
  as?: ElementType
} & TextAlignProps &
  ColorProps &
  ComponentPropsWithoutRef<HeadingTag>

// 基础渲染组件
const HeadingBase = ({ level, as, children, ...props }: HeadingProps) => {
  // 优先使用传入的as标签,否则根据level自动生成对应h标签
  const Component = as ?? (`h${level}` as HeadingTag)
  // 给动态组件做类型标注,解决TS属性校验报错
  const TypedComponent = Component as ElementType
  return <TypedComponent {...props}>{children}</TypedComponent>
}

// 保留原有样式配置逻辑
const headingBaseStyle = css({
  fontFamily: "heading",
  fontWeight: "heading",
})

const levelVariant = variant({
  prop: "level",
  variants: {
    1: { fontSize: 7, lineHeight: 7 },
    2: { fontSize: 6, lineHeight: 6 },
    3: { fontSize: 5, lineHeight: 5 },
    4: { fontSize: 4, lineHeight: 4 },
    5: { fontSize: 3, lineHeight: 3 },
    6: { fontSize: 2, lineHeight: 2 },
  },
})

// 生成最终的styled组件
const Heading = styled(HeadingBase)<HeadingProps>(
  headingBaseStyle,
  levelVariant,
  textAlign,
  color
)

export default Heading

实际使用示例

  • 基础用法:根据level自动渲染对应标签,匹配对应字号行高
    {/* 自动渲染h2标签,应用二级标题样式 */}
    <Heading level={2} color="primary.600" textAlign="center">页面二级标题</Heading>
    
  • 特殊场景覆盖:手动指定as标签,保留原有标题样式
    {/* 渲染为div标签,应用三级标题样式 */}
    <Heading level={3} as="div">自定义容器的三级标题</Heading>
    

实现注意点:

  • 不需要在外部把level和as做强制绑定,用户只需要传入level就可以自动渲染正确的标题标签,as参数仅作为特殊场景的出口,不会干扰默认逻辑
  • 显式的类型断言是为了兼容TS低版本的类型推断缺陷,在TS 5.0+版本中,h${level}的模板字面量可以自动匹配React的HTML标签类型定义,类型报错会自动消失

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.26 22:36:03