无法正确键入以下 HOC 函数
Can't properly type the following HOC function
我写了一个我无法正确输入的 HOC 函数(这是预料之中的,因为我是 TypeScript 初学者,甚至是类型初学者)。这是函数:
const withLayout = (LayoutComponent, layoutProps = {}) => (WrappedComponent) => {
return function WithLayout(props) {
return (
<LayoutComponent {...layoutProps}>
<WrappedComponent {...props} />
</LayoutComponent>
)
}
}
我是这样使用的:
interface LayoutProps { a: string, b: string }
interface IndexProps { c: string, d: string }
class Layout extends React.Component<LayoutProps> { }
class Index extends React.Component<IndexProps> { }
withLayout(Layout, { a: 'a', b: 'b' })(Index)
这是我尝试输入的:
const withLayout = <LP extends JSX.IntrinsicAttributes & { children?: React.ReactNode }>(
LayoutComponent: React.ComponentType<LP>,
layoutProps: LP = {}
) => <WP extends JSX.IntrinsicAttributes & { children?: React.ReactNode }>(
WrappedComponent: React.ComponentType<WP>
) => {
return function WithLayout(props: WP): JSX.Element {
return (
<LayoutComponent {...layoutProps}>
<WrappedComponent {...props} />
</LayoutComponent>
)
}
}
我有几个问题,正如您在 TypeScript playground 中看到的那样。我意识到我应该允许 layoutProps
和 props
分别成为 LayoutComponent
和 WrappedComponent
道具的对象,但我真的想不出正确的方法将它传达给 TypeScript。有什么建议吗?
问题 #1:默认道具
参数 layoutProps
必须是 LP
类型,其中 LP
是布局组件的属性。您不能使用空对象作为 layoutProps
的默认值,因为它没有所需的道具。我们根本不能有默认值,因为我们不知道 LP
是什么,所以我们不可能满足未知类型的要求。
问题 #2:extends
类型
您声明 LayoutComponent
和 WrappedComponent
的属性必须扩展 JSX.IntrinsicAttributes & { children?: React.ReactNode }
。此类型中没有必需的属性,因此技术上您的组件应该可以分配给它,但缺少重叠会导致 Typescript 类型推断阻塞。
我们应该得到更有用的错误,例如“这些类型没有共同的属性”。相反,它只是不推断类型。它使用你的 extends
子句作为类型,然后给你一个错误,这些道具 JSX.IntrinsicAttributes & { children?: React.ReactNode }
不能用作组件的道具,因为它们缺少组件所需的属性。
我们可以简单地通过扩大 extends
条件(甚至完全删除它)来解决这个问题。使用 LP extends {}
,可以正确推断组件的实际 props。
const withLayout = <LP extends {}>(
LayoutComponent: React.ComponentType<LP>,
layoutProps: LP
) => <WP extends {}>(
WrappedComponent: React.ComponentType<WP>
) => {
return function WithLayout(props: WP): JSX.Element {
return (
<LayoutComponent {...layoutProps}>
<WrappedComponent {...props} />
</LayoutComponent>
)
}
}
我写了一个我无法正确输入的 HOC 函数(这是预料之中的,因为我是 TypeScript 初学者,甚至是类型初学者)。这是函数:
const withLayout = (LayoutComponent, layoutProps = {}) => (WrappedComponent) => {
return function WithLayout(props) {
return (
<LayoutComponent {...layoutProps}>
<WrappedComponent {...props} />
</LayoutComponent>
)
}
}
我是这样使用的:
interface LayoutProps { a: string, b: string }
interface IndexProps { c: string, d: string }
class Layout extends React.Component<LayoutProps> { }
class Index extends React.Component<IndexProps> { }
withLayout(Layout, { a: 'a', b: 'b' })(Index)
这是我尝试输入的:
const withLayout = <LP extends JSX.IntrinsicAttributes & { children?: React.ReactNode }>(
LayoutComponent: React.ComponentType<LP>,
layoutProps: LP = {}
) => <WP extends JSX.IntrinsicAttributes & { children?: React.ReactNode }>(
WrappedComponent: React.ComponentType<WP>
) => {
return function WithLayout(props: WP): JSX.Element {
return (
<LayoutComponent {...layoutProps}>
<WrappedComponent {...props} />
</LayoutComponent>
)
}
}
我有几个问题,正如您在 TypeScript playground 中看到的那样。我意识到我应该允许 layoutProps
和 props
分别成为 LayoutComponent
和 WrappedComponent
道具的对象,但我真的想不出正确的方法将它传达给 TypeScript。有什么建议吗?
问题 #1:默认道具
参数 layoutProps
必须是 LP
类型,其中 LP
是布局组件的属性。您不能使用空对象作为 layoutProps
的默认值,因为它没有所需的道具。我们根本不能有默认值,因为我们不知道 LP
是什么,所以我们不可能满足未知类型的要求。
问题 #2:extends
类型
您声明 LayoutComponent
和 WrappedComponent
的属性必须扩展 JSX.IntrinsicAttributes & { children?: React.ReactNode }
。此类型中没有必需的属性,因此技术上您的组件应该可以分配给它,但缺少重叠会导致 Typescript 类型推断阻塞。
我们应该得到更有用的错误,例如“这些类型没有共同的属性”。相反,它只是不推断类型。它使用你的 extends
子句作为类型,然后给你一个错误,这些道具 JSX.IntrinsicAttributes & { children?: React.ReactNode }
不能用作组件的道具,因为它们缺少组件所需的属性。
我们可以简单地通过扩大 extends
条件(甚至完全删除它)来解决这个问题。使用 LP extends {}
,可以正确推断组件的实际 props。
const withLayout = <LP extends {}>(
LayoutComponent: React.ComponentType<LP>,
layoutProps: LP
) => <WP extends {}>(
WrappedComponent: React.ComponentType<WP>
) => {
return function WithLayout(props: WP): JSX.Element {
return (
<LayoutComponent {...layoutProps}>
<WrappedComponent {...props} />
</LayoutComponent>
)
}
}