React TypeScript HoC - 将组件作为道具传递

Posted

技术标签:

【中文标题】React TypeScript HoC - 将组件作为道具传递【英文标题】:React TypeScript HoC - passing Component as the prop 【发布时间】:2018-08-22 18:28:57 【问题描述】:

按照本教程进行操作:https://reacttraining.com/react-router/web/example/auth-workflow。

试图重现代码:

const PrivateRoute = ( component: Component, ...rest ) => (
  <Route
    ...rest
    render=props =>
      fakeAuth.isAuthenticated ? (
        <Component ...props />
      ) : (
        <Redirect
          to=
            pathname: "/login",
            state:  from: props.location 
          
        />
      )
    
  />
);

在 TypeScript 中:

import * as React from 'react';
import  Route, RouterProps  from 'react-router';

interface Props extends RouterProps 
  component: React.Component;


const PrivateRoute = ( component: Component, ...rest : Props) => 
  return (
    <Route
      ...rest
      render=(props) => <Component ...props />
    />
  );
;

export default PrivateRoute;

但它总是会失败。尝试了不同的变化。我最近发布的一个。获取:

在我看来,我必须为 Component 类型传递 Generic,但我不知道如何。

编辑:

迄今为止最接近的解决方案:

interface Props extends RouteProps 
  component: () => any;


const PrivateRoute = ( component: Component, ...rest : Props) => 
  return (
    <Route
      ...rest
      render=(props) => <Component ...props />
    />
  );
;

然后:

<PrivateRoute component=Foo path="/foo" />

【问题讨论】:

【参考方案1】:

你想传递一个组件构造函数,而不是一个组件实例:

import * as React from 'react';
import  Route, RouteProps  from 'react-router';

interface Props extends RouteProps 
    component: React.ComponentType;


const PrivateRoute = ( component: Component, ...rest : Props) => 
    return (
        <Route
            ...rest
            render=(props) => <Component ...props />
        />
    );
;

export default PrivateRoute;

class Foo extends React.Component 


let r = <PrivateRoute component=Foo path="/foo" />

编辑

更完整的解决方案应该是通用的并使用RouteProps 而不是RouterProps

import * as React from 'react';
import  Route, RouteProps  from 'react-router';

type Props<P> =  RouteProps & P & 
    component: React.ComponentType<P>;


const PrivateRoute = function <P>(p: Props<P>) 
    // We can't use destructuring syntax, because : "Rest types may only be created from object types", so we do it manually.
    let rest = omit(p, "component");
    let Component = p.component;
    return (
        <Route
            ...rest
            render=(props: P) => <p.component ...props />
        />
    );
;

// Helpers
type Diff<T extends string, U extends string> = ([P in T]: P  & [P in U]: never  &  [x: string]: never )[T];  
type Omit<T, K extends keyof T> = Pick<T, Diff<keyof T, K>>; 
function omit<T, TKey extends keyof T>(value:T, ... toRemove: TKey[]): Omit<T, TKey>
    var result = Object.assign(, value);
    for(let key of toRemove)
        delete result[key];
    
    return result;



export default PrivateRoute;

class Foo extends React.Component< prop: number >


let r = <PrivateRoute component=Foo path="/foo" prop=10 />

【讨论】:

这似乎是朝着正确的方向发展。但是不确定在这种情况下如何使用PrivateRoute。像&lt;PrivateRoute component=Foo path="/foo" /&gt; 这样的东西会给出属性不匹配错误。因此,任何一个都使用与React.Component 不同的smth,或者在使用PrivateRoute 时提供不同的props @Oleg 将解决方案更新为通用的,并将 RouterProps 的用法更正为 RouteProps 感谢您花时间对此和扩展答案。然而,这似乎是一个矫枉过正。我已经用最接近目标代码的方式更新了描述。现在的任务是为component 找到正确的签名。根据github.com/ReactTraining/react-router/blob/master/packages/… - 这只是一个功能。调试器将其指向为() =&gt; Element,但这不起作用。 @Oleg 如果通用版本是矫枉过正(我不一定认为这是因为你会重复使用它,但这是你的决定)为什么第一个解决方案不起作用?我包含了它的完整代码,它为我编译。你有什么问题吗?【参考方案2】:

经过几个小时和一些调查,这里是符合我要求的解决方案:

import * as React from 'react';
import  Route, RouteComponentProps, RouteProps  from 'react-router';

const PrivateRoute: React.SFC<RouteProps> =
  ( component: Component, ...rest ) => 
    if (!Component) 
      return null;
    
    return (
      <Route
        ...rest
        render=(props: RouteComponentProps<>) => <Component ...props />
      />
    );
  ;

export default PrivateRoute;

没有any; 没有额外的复杂性; 组合模式保留;

【讨论】:

我认为你的最后一行是export default PrivateRoute;

以上是关于React TypeScript HoC - 将组件作为道具传递的主要内容,如果未能解决你的问题,请参考以下文章

TypeScript React HOC 返回类型与装饰器兼容

如何在 TypeScript 中为 React Apollo Query 组件编写 HOC?

React TypeScript HoC - 将组件作为道具传递

Typescript with React - 在通用组件类上使用 HOC

Typescript 无状态 HOC react-redux 注入道具打字

我可以在 React 的 JSX / TSX 中直接调用 HOC 吗?