首页 > 解决方案 > JSX 元素的包装函数,通过泛型输入

问题描述

目前此功能工作正常

function wrapElement(elem: JSX.Element) {
  return ({ ...props }) => React.cloneElement(elem, { ...props })
}

我这样使用它,因为这样我可以获得顺风类的智能感知

const Btn = wrapElement(<button className="[A LOT OF TAILWIND UTILITY CLASSES]" />)

但我试图让它返回与接收到的相同的类型,所以我可以获得 intelliSense 用于内在 HTML 元素的属性。现在推断的类型是

function wrapElement(elem: JSX.Element): ({ ...props }: {
    [x: string]: any;
}) => React.FunctionComponentElement<any>.FunctionComponentElement<any> 

我尝试了一些东西,但都因各种错误而失败,在这一点上感觉这可能是 hacky,但也许我不明白什么?

标签: reactjstypescriptgenerics

解决方案


基本上不可能JSX.Element. 您可以实现您想要的设计,但您应该将元素名称和道具作为单独的参数传递,而不是传递JSX.Element.

此代码可以接受元素名称'button'或任何 React 组件。它返回一个具有相同道具的函数组件。我没有从返回的组件中删除任何道具,因为您似乎正在使用它来设置默认值而不是删除要求。

import React, { ComponentType, ComponentProps } from "react";

const wrapElement = <
  C extends keyof JSX.IntrinsicElements | ComponentType<any>
>(
  Component: C,
  presetProps: Partial<ComponentProps<C>>
) => (props: ComponentProps<C>) => {
  const merged: ComponentProps<C> = { ...presetProps, ...props };
  return <Component {...merged} />;
};

const Btn = wrapElement("button", {
  className: "[A LOT OF TAILWIND UTILITY CLASSES]"
});

const Dbl = wrapElement(Btn, { onClick: () => alert("clicked") });

const Test = () => {
  return <Dbl>Click</Dbl>;
};

打字稿游乐场链接

您可能希望自定义合并行为以组合classNamestyle属性,而不是覆盖它们。

注意:当我尝试合并 props inline 时,<Component {...presetProps} {...props} />我遇到了一个奇怪的错误“Type Partial<ComponentProps<C>> & ComponentProps<C>is not assignable to type IntrinsicAttributes & LibraryManagedAttributes<C, any>。” 所以这就是为什么我在单独的行上合并道具并将类型注释为ComponentProps<C>而不是推断类型Partial<ComponentProps<C>> & ComponentProps<C>


推荐阅读