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

如何为带子组件的ForwardRef组件添加TypeScript类型声明?

为带子组件的ForwardRef React组件添加TypeScript类型声明

我需要创建一个包含子组件(SubComponents)的React组件,该组件要配合useImperativeHandle使用,因此必须用forwardRef。

原始JavaScript实现代码

const MyComponent = Object.assign(forwardRef(function(props, ref){
    useImperativeHandle(ref, () => ({
        toggle: function(){ /*TODO*/ }
    }));
    return <div className="MyComponent" {...props}>
        {props.children || <MyComponent.Sub />}
    </div>
}),{
    Sub: function(props){
        return <div className="MyComponent_Sub">{props.children}</div>
    }
});
export default MyComponent;

我的TypeScript类型尝试过程

普通函数组件的类型声明(正常工作)

import { FC, PropsWithChildren, HTMLProps } from 'react';

interface MyComponentProps extends PropsWithChildren {
    // 自定义属性
}

const MyComponent: FC<MyComponentProps & HTMLProps<HTMLDivElement>> = function(props){
    return <div {...props}></div>
}

export default MyComponent;

带子组件的普通函数组件的类型声明(正常工作)

这里子组件必须通过点语法声明,Object.assign无法生效:

import { FC, PropsWithChildren, HTMLProps } from 'react';

interface MyComponentProps extends PropsWithChildren {
    // 自定义属性
}

interface MyComponentSubs {
    Sub: FC<HTMLProps<HTMLSpanElement>>,
    // 其他子组件
}

const MyComponent: FC<MyComponentProps & HTMLProps<HTMLDivElement>> & MyComponentSubs = function(props){
    return <div {...props}>
      {props.children || <MyComponent.Sub />}
    </div>
}

MyComponent.Sub = function(props){
    return <span {...props}>{props.children}</span>
}
export default MyComponent;

ForwardRef组件的类型尝试(失败写法)

这种写法下props无法被正确解析,props.ref不应该被访问到:

import { ForwardRefExoticComponent, PropsWithChildren, useImperativeHandle, forwardRef } from 'react';

interface MyComponentProps extends PropsWithChildren {
    // 自定义属性
}

interface MyComponentAPI {
    toggle: () => void
}

const MyComponent: ForwardRefExoticComponent<MyComponentProps & React.RefAttributes<MyComponentAPI>> = forwardRef(function(props, ref){
    useImperativeHandle(ref, () => ({
        toggle: function(){/*TODO*/}
    }));
    props.ref; // 此处不应该能访问到props.ref
    return <div {...props}>{props.children}</div>
})

ForwardRef组件的正确类型写法(仅主组件,无带子组件)

只有这种写法能正常工作,但不知道如何添加子组件的类型:

import { PropsWithChildren, useImperativeHandle, forwardRef } from 'react';

interface MyComponentProps extends PropsWithChildren {
    // 自定义属性
}

interface MyComponentAPI {
    toggle: () => void
}

const MyComponent = forwardRef<MyComponentAPI, MyComponentProps>(function(props, ref){
    useImperativeHandle(ref, () => ({
        toggle: function(){/*TODO*/}
    }));
    return <div {...props}>{props.children}</div>
})

带子组件的ForwardRef组件类型尝试(失败)

我尝试了以下写法但无法运行:

import { ForwardRefExoticComponent, PropsWithChildren, useImperativeHandle, forwardRef, createElement, FC, HTMLProps } from 'react';

interface MyComponentProps extends PropsWithChildren {
    // 自定义属性
}

interface MyComponentAPI {
    toggle: () => void
}

interface MyComponentSubs {
    Sub: FC<HTMLProps<HTMLSpanElement>>
}

const MyForwardComponentWithSubs: ForwardRefExoticComponent<MyComponentProps> & MyComponentSubs = forwardRef(function(props, ref){
    useImperativeHandle(ref, () => ({
        toggle: function(){/*TODO*/}
    }));

    return <div {...props}>{props.children}</div>
});

MyForwardComponentWithSubs.Sub = function(props){
    return createElement("span", props, props.children);
}

疑问

是否可以像最初的JavaScript代码那样使用Object.assign?或者有没有更简单的实现方式?

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 14:04:58