TypeScript React项目集成redux-auth-wrapper:HOC包裹组件需手动传入注入props的类型错误求助
我明白你遇到的问题了——当你用redux-auth-wrapper的高阶组件(HOC)包裹组件后,直接用JSX语法<SubServiceOverview />渲染时,TypeScript会报错要求你传入HOC本该自动注入的props,比如redirect、isAuthenticated这些。而把组件传给Route的component属性时就没问题,这是因为Route的component属性会自动处理props传递,而直接渲染JSX时TypeScript会严格检查组件的props类型。
下面是具体的排查和解决方法:
原因分析
你的userIsAuthenticated HOC在类型定义上,把InjectedAuthRouterProps和组件自身的props合并后作为了包裹后组件的props类型,这就导致TypeScript认为你需要手动传入这些HOC本该注入的props。实际上,这些props是由HOC内部提供的,不需要外部传入。
解决方案
方案1:修正HOC的类型定义(推荐)
调整reduxAuth.ts中的makeUserIsAuthenticated函数的类型,确保包裹后的组件只需要接收自身的props,而HOC注入的props不会被要求外部传入:
// reduxAuth.ts import { routerActions } from "connected-react-router"; import { AuthWrapperDecorator } from "redux-auth-wrapper"; import { connectedRouterRedirect, InjectedAuthRouterProps } from "redux-auth-wrapper/history4/redirect"; import { RootState } from "state/configureStore"; import { REDUCER_NAME } from "state/user/constants"; const authenticatedSelector = (state: RootState) => state[REDUCER_NAME] && state[REDUCER_NAME]["authenticated"]; // 修改返回类型:去掉 & InjectedAuthRouterProps,因为这些是HOC内部注入的,无需外部传入 export const makeUserIsAuthenticated = <OwnProps = Record<string, unknown>>(): AuthWrapperDecorator<OwnProps> => connectedRouterRedirect<OwnProps, RootState>({ redirectPath: "/login", authenticatedSelector, wrapperDisplayName: "UserIsAuthenticated", redirectAction: routerActions.replace }); export const userIsAuthenticated = makeUserIsAuthenticated<Record<string, unknown>>();
然后,确保你的SubServiceOverview组件的props类型明确(如果没有自定义props,就用默认的{}):
// SubServiceOverview.tsx import React from "react"; import { Link } from "react-router-dom"; import { userIsAuthenticated } from "libs/reduxAuth"; import services from "routes/services"; // 明确组件不需要外部传入props const ServiceOverview: React.FC<{}> = () => { return ( <div> <ul> {services.map(service => ( <li key={service.name}> <Link to={`/services/${service.name}`}>{service.name}</Link> </li> ))} </ul> </div> ); }; export default userIsAuthenticated(ServiceOverview);
这样修改后,TypeScript就不会再要求你传入HOC注入的props了,直接用<SubServiceOverview />渲染就正常了。
方案2:使用Route的render属性替代直接渲染JSX
如果你不想修改HOC的类型定义,也可以在Routes.tsx中使用Route的render属性来渲染组件,这样TypeScript不会严格检查组件的props:
// Routes.tsx <Route path="/services/:subService" render={() => <SubServiceOverview />} />
这种方法简单快速,但属于绕过类型检查的临时方案,不如方案1规范。
方案3:明确组件的props类型(不推荐)
如果你想保留当前的HOC类型定义,可以让组件的props继承InjectedAuthRouterProps并标记这些props为可选,但这会让组件类型不够严谨,因为这些props本不该由外部传入:
// SubServiceOverview.tsx import React from "react"; import { Link } from "react-router-dom"; import { userIsAuthenticated, InjectedAuthRouterProps } from "libs/reduxAuth"; import services from "routes/services"; // 标记HOC注入的props为可选 const ServiceOverview: React.FC<Partial<InjectedAuthRouterProps>> = () => { return ( <div> <ul> {services.map(service => ( <li key={service.name}> <Link to={`/services/${service.name}`}>{service.name}</Link> </li> ))} </ul> </div> ); }; export default userIsAuthenticated(ServiceOverview);
验证
修改完成后重新编译项目,TypeScript的错误应该就会消失了。另外,Login组件没有报错是因为你把它传给了Route的component属性,Route会自动处理props传递,HOC也能正确注入需要的props。
内容的提问来源于stack exchange,提问作者Arnab Das

