如何为带子组件的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
相关产品推荐
相关产品推荐

