如何用TypeScript实现为ErrorBoundary提供location的高阶组件(HOC)
解决React Router WithRouter HOC的TypeScript类型问题
我尝试用TypeScript实现一个高阶组件(HOC),将ErrorBoundary组件传入该HOC,让HOC注入用户当前的location属性,以便在ErrorBoundary中使用。现有TypeScript版本的HOC编译报错,JavaScript版本可正常运行,但无法正确转换为TypeScript版本。
现有ErrorBoundary组件代码
import React from "react"; interface ErrorBoundaryProps { fallback: React.ReactNode; children: React.ReactNode; location: { pathname: string; }; } class ErrorBoundary extends React.Component<ErrorBoundaryProps> { state = { hasError: false }; static getDerivedStateFromError(error: Error) { return { hasError: true }; } componentDidUpdate(previousProps: ErrorBoundaryProps) { if (previousProps.location.pathname !== this.props.location.pathname) { this.setState({ hasError: false }); } } render() { if (this.state.hasError) { return this.props.fallback; } return this.props.children; } } export default ErrorBoundary;
报错的WithRouter HOC代码
import { useLocation } from "react-router-dom"; function WithRouter(OriginalComponent: React.ComponentType) { const NewComponent = (props: any) => { const location = useLocation(); return <OriginalComponent {...props} location={location} />; }; return NewComponent; }
正确的TypeScript实现方案
核心是通过泛型明确HOC的类型约束,避免使用any,同时确保注入的location属性与组件所需类型匹配:
import { useLocation, Location } from "react-router-dom"; import React from "react"; // 泛型HOC:T为组件接收的props(排除location,由HOC注入) function WithRouter<T extends Omit<ErrorBoundaryProps, 'location'>>( OriginalComponent: React.ComponentType<T & { location: Location }> ) { const NewComponent: React.FC<T> = (props) => { const location = useLocation(); // 注入location并传递其他props return <OriginalComponent {...props} location={location} />; }; // 保留原组件displayName,方便调试 NewComponent.displayName = `WithRouter(${OriginalComponent.displayName || OriginalComponent.name})`; return NewComponent; }
关键类型说明
- 泛型
T接收组件的原始props(排除location,因为HOC会自动注入) - 约束
OriginalComponent的props为T & { location: Location },确保组件能接收注入的路由location对象 NewComponent的props类型为T,外部使用时无需手动传递location- 保留原组件的
displayName,提升React DevTools的调试体验
使用方式
// 生成带location注入的ErrorBoundary组件 const ErrorBoundaryWithRouter = WithRouter(ErrorBoundary); // 使用时无需传递location <ErrorBoundaryWithRouter fallback={<div>出错了</div>}> {/* 子组件内容 */} </ErrorBoundaryWithRouter>
内容的提问来源于stack exchange,提问作者Hussein Khodor
相关产品推荐
相关产品推荐

