React Redux TS高阶组件connect包装报ComponentType<never>类型错误
问题描述
实现ErrorBoundary高阶组件(HOC)时,尝试用react-redux的connect方法对其包装,抛出类型错误:typeof [a class] is not assignable to parameter of type 'ComponentType<never>',报错截图如下:
已经按定义向HOC传入对应属性,但仍有报错,相关实现代码如下:
interface State { error: unknown; info: unknown; } interface WithErrorBoundaryProps { getNotification(...args: any): void; } const withErrorBoundary = <P extends WithErrorBoundaryProps>( TargetComponent: React.ComponentType<P> ) => { class ErrorBoundary extends React.PureComponent<P, State> { public state: State = { error: null, info: null, }; public componentDidCatch(error: Error, errorInfo: ErrorInfo) { getNotification({ alertType: 'error', message: error.message }); this.setState({ error, info: errorInfo }); } public render() { const { ...props } = this.props; if (this.state.error instanceof Error) { return <Alert type="error">{this.state.error?.message}</Alert>; } return <TargetComponent {...(props as P)} />; } } return ErrorBoundary; }; export const connectedErrorBoundary = connect(null, { getNotification: getNotificationAction, })(withErrorBoundary);
报错原因
- 核心逻辑错误:
connect方法的入参必须是一个合法的React组件(类组件/函数组件),但代码中直接把withErrorBoundary这个接收组件、返回新组件的HOC函数传给了connect,不符合组件类型要求。 - 类型推断失败:由于传入的是HOC函数而非组件,TS无法推导HOC需要的泛型参数,默认将组件Props类型推断为
never,最终抛出类型不匹配错误。 - 隐性逻辑问题:
componentDidCatch生命周期中直接调用getNotification,但该方法是需要connect注入到props中的,全局作用域下不存在该方法,运行时会报未定义错误。
修复方案
- 调整
connect调用位置:不要在HOC外部包装HOC本身,改为在HOC内部对最终返回的ErrorBoundary类组件做connect包装,让redux把getNotification方法正确注入到组件props中。 - 修正方法调用逻辑:在
componentDidCatch中从this.props读取注入的getNotification方法,不要直接调用全局未定义变量。 - 拆分类型定义:区分redux注入的Props、透传给目标组件的Props,避免泛型推断冲突。
修复后的完整代码:
import React, { ComponentType, PureComponent, ErrorInfo } from 'react'; import { connect } from 'react-redux'; import { Alert } from 'your-ui-library-path'; import { getNotification as getNotificationAction } from 'your-store-action-path'; // ErrorBoundary内部状态类型 interface ErrorBoundaryState { error: Error | null; info: ErrorInfo | null; } // redux connect注入的Props类型 interface InjectedProps { getNotification: (...args: any[]) => void; } const withErrorBoundary = <P extends object>( TargetComponent: ComponentType<P> ) => { // 内部ErrorBoundary组件Props = 透传给目标组件的Props + 注入的Props class ErrorBoundary extends PureComponent<P & InjectedProps, ErrorBoundaryState> { public state: ErrorBoundaryState = { error: null, info: null, }; public componentDidCatch(error: Error, errorInfo: ErrorInfo) { // 从props中读取注入的通知方法 this.props.getNotification({ alertType: 'error', message: error.message }); this.setState({ error, info: errorInfo }); } public render() { // 拆分注入props和透传props,避免redux注入的属性被透传到目标组件 const { getNotification, ...targetProps } = this.props; if (this.state.error) { return <Alert type="error">{this.state.error.message}</Alert>; } return <TargetComponent {...(targetProps as P)} />; } } // 在HOC内部connect包装ErrorBoundary组件 const ConnectedErrorBoundary = connect(null, { getNotification: getNotificationAction, })(ErrorBoundary); return ConnectedErrorBoundary; }; export default withErrorBoundary;
使用方式:
// 用HOC包裹业务组件即可,不需要手动传入getNotification,redux会自动注入 const YourBusinessComponent = (props: { id: string }) => { return <div>业务组件</div> } export default withErrorBoundary(YourBusinessComponent);
内容的提问来源于stack exchange,提问作者Samira Arabgol
相关产品推荐
相关产品推荐

