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

使用TypeScript能否基于props动态渲染带类型校验的React元素?

解决方案

你要的提取公共中央组件的实现方案完全可行,核心通过泛型联合类型+元素类型断言处理不同标签的属性类型匹配,既能完全抽离公共逻辑,又能保证TS类型校验正常,不会出现跨元素属性透传的错误。

第一步:定义泛型属性类型

import React from 'react';
import { IconDefinition } from '@fortawesome/fontawesome-svg-core';

type Variant = "primary" | "secondary" | "tertiary";

// 原有公共配置属性保留
interface CommonProps {
  variant?: Variant;
  showChevron?: boolean;
  icon?: IconDefinition;
  fullWidth?: boolean;
  small?: boolean;
}

// 支持的基础标签类型
type SupportedElement = 'a' | 'button';

// 泛型属性:根据传入的标签类型,自动匹配对应原生属性
type ComponentProps<T extends SupportedElement> = CommonProps & {
  element: T;
// 保留你原有属性的必填约束:Link必须传href,Button必须传onClick
} & (T extends 'a' 
  ? React.AnchorHTMLAttributes<HTMLAnchorElement> & { href: string } 
  : React.ButtonHTMLAttributes<HTMLButtonElement> & { onClick: React.MouseEventHandler<HTMLButtonElement> }
);

第二步:实现公共中央组件

所有公共逻辑(样式计算、内容渲染)都在这里统一维护:

// 复用你原有逻辑即可
const initButton = (props: CommonProps) => {
  // 原有样式计算逻辑
  return { classes: 'calculated-class-names' };
};
const Content = (props: CommonProps & { children?: React.ReactNode }) => {
  // 原有内容渲染逻辑:处理图标、V形标识、文字展示
  return <>{props.children}</>;
};

// 泛型公共组件
const Component = <T extends SupportedElement>({ 
  element, 
  children, 
  className, 
  ...rest 
}: ComponentProps<T>) => {
  const { classes } = initButton(rest);
  const combinedClasses = `${classes} ${className || ''}`.trim();

  // 类型断言告知TS当前渲染标签和传入属性完全匹配
  const Element = element as React.ElementType;
  return (
    <Element className={combinedClasses} {...rest}>
      <Content {...rest}>{children}</Content>
    </Element>
  );
};

第三步:封装独立的Link和Button组件

和你期望的写法完全一致,仅做最简包装,调用时意图清晰:

// Link组件:固定渲染a标签,继承a标签所有属性约束
export const Link = (props: Omit<ComponentProps<'a'>, 'element'>) => {
  return <Component element="a" {...props} />;
};

// Button组件:固定渲染button标签,继承button标签所有属性约束
export const Button = (props: Omit<ComponentProps<'button'>, 'element'>) => {
  return <Component element="button" {...props} />;
};

效果说明

  • 调用组件时类型校验完全正常:Link组件要求必须传入href,Button组件要求必须传入onClick,不会出现跨标签属性误传的问题
  • 后续修改公共逻辑仅需调整Component组件,两个包装组件自动同步更新,无需重复修改代码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 01:27:07