有可能在Typescript中创建严格类型的React HOC吗?



作为上下文,我正在尝试创建一个更高阶的组件来包装React Native组件,并基于对组件的引用添加一些功能。

简短的未类型化示例:

export function withHelper(WrappedEl) {
return ({
layoutParam,
onChangeLayout,
...wrappedElProps
}) => {
const ref = useRef(null);
const onLayout = useCallback(() => {
ref.current?.measure((_x, _y, width, height, px, py) => {
onChangeLayout({
layout: {
width,
height,
y: py,
x: px,
},
layoutParam,
});
});
}, [
onChangeLayout,
layoutParam,
]);
return <WrappedEl {...wrappedElProps} ref={ref} onLayout={onLayout} />;
};
}

measure是一个React Native元素,它给了我一些关于渲染其他东西的元素的信息。来自NativeMethods接口

我想在这里严格输入:

  • HOC只能用于具有measure方法的元素。
  • 结果组件与所有原始组件的道具以及两个添加的道具(layoutParamonChangeLayout)适当地类型化。

这是我得到的结果:

interface WithHelperProps {
layoutParam: string;
onChangeLayout: (props: {layout: Layout, payoutParam: string}) => void;
}
export function withHelper<
P extends object,
V extends React.ComponentClass<P> & Constructor<NativeMethods>,
>(El: V): React.FC<P & WithHelperProps> {
return ({
layoutParam,
onChangeLayout,
...props
}) => {
const ref = useRef<InstanceType<V>>(null);
const onLayout = useCallback(() => {
ref.current?.measure((_x, _y, width, height, px, py) => {
onChangeLayout({
layout: {
width,
height,
y: py,
x: px,
},
layoutParam,
});
});
}, [
onChangeLayout,
layoutParam,
]);
const passthroughProps: Omit<
PropsWithChildren<P & WithHelperProps>,
keyof WithHelperProps
> = props;
return <El {...passthroughProps} ref={ref} onLayout={onLayout} />;
};
}

但是这不能编译:

Type 'Omit<PropsWithChildren<P & WithHelperProps>, keyof WithHelperProps> & { ref: RefObject<InstanceType<V>>; onLayout: () => void; }' is not assignable to type 'IntrinsicAttributes & IntrinsicClassAttributes<Component<P, any, any> & NativeMethods> & LibraryManagedAttributes<...>'.
Type 'Omit<PropsWithChildren<P & WithHelperProps>, keyof WithHelperProps> & { ref: RefObject<InstanceType<V>>; onLayout: () => void; }' is not assignable to type 'LibraryManagedAttributes<V, Readonly<P>>'.

我已经玩了一段时间,到处搜索,但我不知道我在这里做错了什么。


我在Replit中做了一个最小的复制。

我想你只是忘记了forwardRef你的组件的ref,这是需要的,因为HOC将包装另一个组件。下面是一个简化版本(稍后我会更新到您的特定用例),用于演示。

interface Layout {
height: number
width: number
x: number
y: number
}
interface WithHelperProps {
children?: React.ReactNode
layoutParam: string
onChangeLayout: (props: { layout: Layout, layoutParam: string }) => void
}
const withHelper = <T, P = {}>(
Render: React.ComponentType<P & { ref?: React.Ref<T> }>,
) => {
const HOC = React.forwardRef<T, P & WithHelperProps>(
({ children, ...props }, ref) => {
return (
<Render {...(props as P)} ref={ref}>
{children}
</Render>
)
},
)
return HOC
}

希望有帮助!欢呼声

相关内容

  • 没有找到相关文章

最新更新