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
。像<PrivateRoute component=Foo path="/foo" />
这样的东西会给出属性不匹配错误。因此,任何一个都使用与React.Component
不同的smth,或者在使用PrivateRoute
时提供不同的props
。
@Oleg 将解决方案更新为通用的,并将 RouterProps
的用法更正为 RouteProps
感谢您花时间对此和扩展答案。然而,这似乎是一个矫枉过正。我已经用最接近目标代码的方式更新了描述。现在的任务是为component
找到正确的签名。根据github.com/ReactTraining/react-router/blob/master/packages/… - 这只是一个功能。调试器将其指向为() => 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