使用 recompose 和 typescript 正确输入 HigherOrderComponents
Correct Typing for HigherOrderComponents with recompose and typescript
我目前正在尝试将其重组到我的 React 代码库中。因此,我试图让一些基本的东西起作用,并且我让它起作用了,但我不太确定,如果这是重新组合的正确工作方式。
所以我有以下代码:
interface Value {
value: string
}
interface Loading {
loading: boolean
}
const TestComponent = (props: Value) => <div>Value: {props.value}</div>
const LoadingComponent = () => <div>Loading ...</div>
所以我有一个 TestComponent,它应该显示 props 中提供的值,另外我还有一个 LoadingComponent,它应该在设置加载 props 时显示。
所以我使用了recompose的branch
功能
const withLoading = branch<Loading>(
({loading}) => loading,
renderComponent(LoadingComponent)
)
现在,当我在 任何没有道具的组件上使用 withLoading
时 我可以在它们上设置加载道具。
const EnhancedCompWithLoading = withLoading(SomeCompWithoutProps)
render() {
return <EnhancedCompWithLoading loading={this.state.loading} />
}
这对我来说很好,真正的问题是在尝试将它与带有道具的组件一起使用时开始。当我这样尝试时:
const TestWithLoading = withLoading(TestComponent)
render() {
return <TestWithLoading value="testVal" loading={this.state.loading} />
}
我收到错误消息 TS2339: Property 'value' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<Loading, any, any>>
& Readonly<{ children?: ReactNode; }> & Readonly<Loading>'.
所以我查看了@types/recompose 中的类型定义。 branch<TOutter>
return 一个 ComponentEnhancer<any,TOutter>
。据我所知,我希望能够提供 any
组件,而 <TOutter>
泛型就是这样,因此生成的组件知道测试功能所需的道具。那也可以在没有附加道具的情况下工作。
但是 ComponentEnhancer 的 TypeDefinition 看起来像这样(重构 0.30.2):
interface ComponentEnhancer<TInner, TOutter> {
(component: Component<TInner>): ComponentClass<TOutter>
}
因此,我从之前的 branch
函数收到的 ComponentEnhancer<any, Loading>
将 return 变成 ComponentClass<Loading>
。但是,我提供给 ComponentEnhancer 的组件的 <TInner>
将被丢弃,我无法在增强组件中使用我的 Value
道具。
所以我的问题是,我是不是做错了,有没有更好的方法来实现这个(通过重组)。或者它只是 TypeDeclaration 中的一个错误,因为将 ComponentEnhancer
的 return 更改为 ComponentClass<TOutter & TInner>
为我修复了整个问题。
对此有什么想法吗?
我不熟悉 branch
和 recompose
,但如果这只是打字问题,我们可以解决。
问题是 branch
的类型不是很好。如果目的是将包装组件的属性转发到 HOC 并将显式输入 branch
的 props 添加到 HOC,那么更好的结果类型是:
type BetterComponentEnhancer<TOutter> = {
<TInner>(component: React.ComponentType<TInner>): React.ComponentClass<TInner & TOutter>
}
对于这种类型,这将起作用:
const withLoading = branch<Loading>(
({ loading }) => loading,
renderComponent(LoadingComponent)
)as unknown as BetterComponentEnhancer<Loading>
type BetterComponentEnhancer<TOutter> = {
<TInner>(component: React.ComponentType<TInner>): React.ComponentClass<TInner & TOutter>
}
const TestWithLoading = withLoading(TestComponent)
function render() {
return <TestWithLoading value="testVal" loading={true} />
}
我目前正在尝试将其重组到我的 React 代码库中。因此,我试图让一些基本的东西起作用,并且我让它起作用了,但我不太确定,如果这是重新组合的正确工作方式。
所以我有以下代码:
interface Value {
value: string
}
interface Loading {
loading: boolean
}
const TestComponent = (props: Value) => <div>Value: {props.value}</div>
const LoadingComponent = () => <div>Loading ...</div>
所以我有一个 TestComponent,它应该显示 props 中提供的值,另外我还有一个 LoadingComponent,它应该在设置加载 props 时显示。
所以我使用了recompose的branch
功能
const withLoading = branch<Loading>(
({loading}) => loading,
renderComponent(LoadingComponent)
)
现在,当我在 任何没有道具的组件上使用 withLoading
时 我可以在它们上设置加载道具。
const EnhancedCompWithLoading = withLoading(SomeCompWithoutProps)
render() {
return <EnhancedCompWithLoading loading={this.state.loading} />
}
这对我来说很好,真正的问题是在尝试将它与带有道具的组件一起使用时开始。当我这样尝试时:
const TestWithLoading = withLoading(TestComponent)
render() {
return <TestWithLoading value="testVal" loading={this.state.loading} />
}
我收到错误消息 TS2339: Property 'value' does not exist on type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<Loading, any, any>>
& Readonly<{ children?: ReactNode; }> & Readonly<Loading>'.
所以我查看了@types/recompose 中的类型定义。 branch<TOutter>
return 一个 ComponentEnhancer<any,TOutter>
。据我所知,我希望能够提供 any
组件,而 <TOutter>
泛型就是这样,因此生成的组件知道测试功能所需的道具。那也可以在没有附加道具的情况下工作。
但是 ComponentEnhancer 的 TypeDefinition 看起来像这样(重构 0.30.2):
interface ComponentEnhancer<TInner, TOutter> {
(component: Component<TInner>): ComponentClass<TOutter>
}
因此,我从之前的 branch
函数收到的 ComponentEnhancer<any, Loading>
将 return 变成 ComponentClass<Loading>
。但是,我提供给 ComponentEnhancer 的组件的 <TInner>
将被丢弃,我无法在增强组件中使用我的 Value
道具。
所以我的问题是,我是不是做错了,有没有更好的方法来实现这个(通过重组)。或者它只是 TypeDeclaration 中的一个错误,因为将 ComponentEnhancer
的 return 更改为 ComponentClass<TOutter & TInner>
为我修复了整个问题。
对此有什么想法吗?
我不熟悉 branch
和 recompose
,但如果这只是打字问题,我们可以解决。
问题是 branch
的类型不是很好。如果目的是将包装组件的属性转发到 HOC 并将显式输入 branch
的 props 添加到 HOC,那么更好的结果类型是:
type BetterComponentEnhancer<TOutter> = {
<TInner>(component: React.ComponentType<TInner>): React.ComponentClass<TInner & TOutter>
}
对于这种类型,这将起作用:
const withLoading = branch<Loading>(
({ loading }) => loading,
renderComponent(LoadingComponent)
)as unknown as BetterComponentEnhancer<Loading>
type BetterComponentEnhancer<TOutter> = {
<TInner>(component: React.ComponentType<TInner>): React.ComponentClass<TInner & TOutter>
}
const TestWithLoading = withLoading(TestComponent)
function render() {
return <TestWithLoading value="testVal" loading={true} />
}