扩展forwardRef组件(如ListItem)时的TypeScript错误排查
解决forwardRef组件挂载静态属性的TypeScript类型错误
问题根源在于:forwardRef返回的组件实例在初始化时并没有Placeholder属性,但你直接给ListItem指定了包含Placeholder的ListItemComponent类型,TypeScript会在变量声明时就做类型校验,这时候属性还没加上,自然报错。
下面是几种可行的解决办法:
方法一:分步创建,最后断言类型
先创建不带类型的forwardRef组件,添加静态属性后再断言为目标类型:
import { forwardRef, FunctionComponent, ForwardRefExoticComponent, RefAttributes } from 'react'; type Props = {/* 你的Props定义 */}; type ListItemComponent = ForwardRefExoticComponent<Props & RefAttributes<HTMLDivElement>> & { Placeholder: typeof ListItemPlaceholder; }; // 先不指定类型,创建基础组件 const ListItem = forwardRef<HTMLDivElement, Props>((props, ref) => { // 组件内部逻辑 return <div ref={ref} />; }); const ListItemPlaceholder: FunctionComponent = () => { return <div />; }; // 挂载静态属性 ListItem.Placeholder = ListItemPlaceholder; // 断言类型后导出 export const TypedListItem = ListItem as ListItemComponent;
方法二:用Object.assign一次性构建符合类型的组件
通过Object.assign把forwardRef组件和静态属性合并,直接满足类型要求,无需额外断言:
import { forwardRef, FunctionComponent, ForwardRefExoticComponent, RefAttributes } from 'react'; type Props = {/* 你的Props定义 */}; type ListItemComponent = ForwardRefExoticComponent<Props & RefAttributes<HTMLDivElement>> & { Placeholder: typeof ListItemPlaceholder; }; const ListItemPlaceholder: FunctionComponent = () => { return <div />; }; export const ListItem: ListItemComponent = Object.assign( forwardRef<HTMLDivElement, Props>((props, ref) => { // 组件内部逻辑 return <div ref={ref} />; }), { Placeholder: ListItemPlaceholder } );
方法三:修改类型定义(不推荐,除非允许属性可选)
如果业务上允许Placeholder属性存在或不存在,可以把它设为可选属性,这样初始化时的类型校验就能通过:
import { forwardRef, FunctionComponent, ForwardRefExoticComponent, RefAttributes } from 'react'; type Props = {/* 你的Props定义 */}; // 将Placeholder设为可选属性 type ListItemComponent = ForwardRefExoticComponent<Props & RefAttributes<HTMLDivElement>> & { Placeholder?: typeof ListItemPlaceholder; }; export const ListItem: ListItemComponent = forwardRef<HTMLDivElement, Props>((props, ref) => { // 组件内部逻辑 return <div ref={ref} />; }); const ListItemPlaceholder: FunctionComponent = () => { return <div />; }; ListItem.Placeholder = ListItemPlaceholder;
内容的提问来源于stack exchange,提问作者RedGiant
相关产品推荐
相关产品推荐

