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

React-TypeScript中自动推导forwardRef元素类型的实现方案

自动推导forwardRef中透传元素的类型

可以实现自动推导被透传HTML元素的类型,核心思路是利用TypeScript的条件类型结合React内置的类型工具,提取元素对应的Ref类型,以下是具体实现方案:

1. 核心工具类型定义

借助React内置的类型体系,我们可以封装出通用的类型提取工具:

// 提取指定HTML元素/组件对应的Ref类型
type ExtractElementRef<T extends keyof React.JSX.IntrinsicElements | React.ComponentType<any>> =
  T extends React.ComponentType<any>
    ? React.ElementRef<T>
    : React.JSX.IntrinsicElements[T]['ref'] extends React.Ref<infer R>
      ? R
      : never;

// 提取指定元素包含ref的完整Props类型
type ExtractElementProps<T extends keyof React.JSX.IntrinsicElements | React.ComponentType<any>> =
  React.ComponentPropsWithRef<T>;

2. 通用组件生成方案

如果需要批量封装组件,可以基于上述工具类型写一个通用生成函数,自动推导Ref和Props:

import { forwardRef, ReactNode } from "react";

function createStyledElement<T extends keyof React.JSX.IntrinsicElements>(
  tagName: T,
  baseClassName: string
) {
  type ComponentProps = Omit<ExtractElementProps<T>, 'className'> & {
    children?: ReactNode;
  };
  type ComponentRef = ExtractElementRef<T>;

  return forwardRef<ComponentRef, ComponentProps>((props, ref) => {
    const { children, ...rest } = props;
    return React.createElement(tagName, {
      ref,
      className: baseClassName,
      ...rest
    }, children);
  });
}

// 使用示例:自动推导FancyButton的Ref为HTMLButtonElement
export const FancyButton = createStyledElement('button', 'MyClassName');
// 同理可快速生成其他组件
export const FancyInput = createStyledElement('input', 'InputClassName');

3. 单个组件的简化写法

如果只需要封装单个组件,也可以直接在组件内自动推导类型,无需额外工具函数:

import { forwardRef, ReactNode, ComponentPropsWithRef, ElementRef } from "react";

// 提取button的Props并排除className(自定义样式)
type ButtonProps = Omit<ComponentPropsWithRef<'button'>, 'className'> & {
  children?: ReactNode;
};
// 自动推导Ref类型为HTMLButtonElement
type ButtonRef = ElementRef<'button'>;

export const FancyButton = forwardRef<ButtonRef, ButtonProps>((props, ref) => (
  <button ref={ref} className="MyClassName" {...props}>
    {props.children}
  </button>
));

原理说明

  • React.JSX.IntrinsicElements包含所有HTML元素的属性定义,通过keyof可获取'button'、'input'等元素标识
  • React.ElementRef<T>直接提取元素对应的Ref类型,比如ElementRef<'button'>等价于HTMLButtonElement
  • React.ComponentPropsWithRef<T>提取元素包含ref的完整Props类型,方便通过Omit剔除需要自定义的属性

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 09:55:28