React Recompose 在 Props 上导致 Typescript 错误
Posted
技术标签:
【中文标题】React Recompose 在 Props 上导致 Typescript 错误【英文标题】:React Recompose Causing Typescript Error On Props 【发布时间】:2019-03-30 01:49:22 【问题描述】:我有一个非常基本的有状态组件,我使用 recompose 将多个 HOC 添加到我的组件中(在我的示例中,为了简单起见,我只使用一个)。出于某种原因,打字稿给了我一个关于我的道具进入我的组件的错误。我怎样才能摆脱这个错误?
这是我的代码:
import * as React from 'react';
import connect from 'react-redux';
import compose from 'recompose';
interface IStoreState
readonly sessionState:
authUser: email: string;
interface IAccountPageProps
authUser: email: string
const AccountPage = ( authUser : IAccountPageProps ) =>
<div>
<h1>Account: authUser.email</h1>
</div>
const mapStateToProps = (state: IStoreState) => (
authUser: state.sessionState.authUser,
);
export default compose(
connect(mapStateToProps)
)(AccountPage);
我得到的错误是:
Argument of type '( authUser : IAccountPageProps) => Element' is not assignable to parameter of type 'ComponentType<>'.
Type '( authUser : IAccountPageProps) => Element' is not assignable to type 'StatelessComponent<>'.
Types of parameters '__0' and 'props' are incompatible.
Type ' children?: ReactNode; ' is not assignable to type 'IAccountPageProps'.
Property 'authUser' is missing in type ' children?: ReactNode; '.
如果我不使用 recompose 而是写
export default connect(mapStateToProps)(AccountPage)
我没有收到任何错误。
【问题讨论】:
【参考方案1】:The current typing of compose
非常没用。如果要使用compose
,则必须手动指定原始组件和最终组件的props
类型,并且不会检查您指定的类型是否与您传递的高阶组件列表匹配:
export default compose<IAccountPageProps, >(
connect(mapStateToProps)
)(AccountPage);
我建议不要在 TypeScript 中使用 compose
。
【讨论】:
好的,再次感谢马特。那么显而易见的问题是,您使用什么来代替 Typescript 撰写?我的生产导出如下所示,其中withAuthorization
是我用来验证是否有人登录的 HOC。export default compose(withAuthorization(authCondition), connect(mapStateToProps))(AccountPage);
@JonLamb 你找到这个 HOC 链接的优雅解决方案了吗?
@bert 我所知道的最佳选择是按照 Brian 的回答中所示的顺序应用 HOC。
谢谢老兄,有道理!
或更好 -> 不要使用打字稿【参考方案2】:
compose 的类型允许您指定生成的组件的类型以及可以调用它的组件的类型,这样可以避免错误:
export default compose<IAccountPageProps, >(
connect(mapStateToProps)
)(AccountPage);
不幸的是,compose 无法确保传递给它的函数的类型安全或兼容性。
因此,例如,即使明显无效,也不会产生打字错误:
export default compose<IAccountPageProps, >(
connect(mapStateToProps),
() => 'compose typing allows any function'
)(AccountPage);
嵌套 HOC 调用更安全:
export default
connect(mapStateToProps)(
firstHoc(
secondHoc(
AccountPage
)
)
);
【讨论】:
谢谢 Brian,你用什么代替 compose 来连接 Typescript 中的多个 HOC? 我最终嵌套了 HOC 调用。它不如 compose 风格的方法漂亮,但类型安全是值得的。 @JonLamb 我用答案更新了我的回复,一个演示 compose 问题的示例,以及推荐的方法【参考方案3】:我发现的最佳解决方案是重新声明类型,以便您也获得connect
的类型(包括可用于轻松测试的.WrappedComponent
),否则默认为React.ComponentClass<, any>
这是不正确的,并且没有按照上面@Matt 的示例为您提供有关组件的信息。
使用您的示例,请参阅:
import React, SFC from 'react';
import connect, ConnectedComponentClass from 'react-redux';
export default compose<IAccountPageProps, >(
connect(mapStateToProps)
)(AccountPage) as ConnectedComponentClass<SFC<IAccountPageProps>, >
现在,当您在其他地方使用该组件时,返回的组件在连接包装器中的正确类型为 ConnectedComponentClass<React.StatelessComponent<IAccountPageProps>, >
,现在您还可以访问 connectedComponent 值,例如 .WrappedComponent
。
ConnectedComponentClass
是 react-redux 的类型,因为它是连接组件的最终类型。在一个完美的世界里,这不应该是必要的,但它确实有效。
【讨论】:
不,这不是一个好的解决方案。这只是对更准确类型的类型断言。核心问题是compose
的输入是不安全的,除非改进输入,否则应该避免在 TypeScript 中使用compose
。
好吧,避免使用是一个解决方案,但我真的认为这也是一个解决方案。我们都知道这种缺失,并且类型断言修复了它。导出的函数有一个安全的类型,为了消费者这很好。然后,在内部,通过断言(这是一种 hack)获得正确的签名。还要考虑ConnectedComponentClass
与该签名充分重叠(不需要as unknown
)。这也是可扩展的,因为在我们修复 compose 定义时,您只需要删除断言。以上是关于React Recompose 在 Props 上导致 Typescript 错误的主要内容,如果未能解决你的问题,请参考以下文章
[Recompose] Stream Props to React Children with RxJS
[Recompose] Make Reusable React Props Streams with Lenses
[Recompose] Lock Props using Recompose -- withProps
[Recompose] Create Stream Behaviors to Push Props in React Components with mapPropsStream