一个允许任何html属性的打字稿类型

时间:2020-08-21 10:36:16

标签: reactjs typescript

我',试图创建一个模仿本地html元素的react组件。

问题1:

允许使用有效的html属性

示例:

type TAtt = {
  [key: string]: React.HTMLAttributes<HTMLElement>;
};

const NavAnyValidAttribute: React.FC<TAtt> = props => {
  const { children, ...therest } = props;
  return <nav {...therest}>{children}</nav>;
};

<NavAnyValidAttribute className="x">some children</NavAnyValidAttribute>;

错误

类型'string'与类型'HTMLAttributes'没有共同的属性。(2559) input.tsx(135,3):预期的类型来自此索引签名。

问题2:

type TProps = TAtt & {
  TagName: string; //keyof JSX.IntrinsicElements - also doesn't work!;
}

const Tag: React.FC<TProps> = ({ TagName, children, ...props }) =>
  React.createElement(TagName, props, children);

const Nav = <Tag {...{ TagName: 'nav' }} />;

错误:输入'{TagName:string; }”不可分配给“ TAtt”类型。 属性“ TagName”与索引签名不兼容。 类型“字符串”与类型“ HTMLAttributes”没有共同的属性。ts(2322)

任何帮助表示赞赏。 谢谢

1 个答案:

答案 0 :(得分:0)

好的,我已经创建了一个解决方案。

我敢肯定有更好的方法,但是为了保持严格,并允许将此组件传递给另一个未知的组件处理程序,我必须确保我返回了Component

我还必须确保我拥有严格的TagName:React.ElementType。或“ JSX.IntrinsicElements键”。不确定哪个更合适。但以下两种方法都必须使用相同的方法。

我还必须将GetTagAsComp方法作为同一组件TagAsComp的成员返回。

如果有任何比较简单的方法,请随时添加。

import React from 'react';

type TElem = React.ElementType; // OR keyof JSX.IntrinsicElements;

// Might have to extend this for specific element attributes - see
// - https://www.saltycrane.com/cheat-sheets/typescript/react/latest/
type TAtt = React.HTMLAttributes<HTMLElement>;

type TCreateElement = {
  TagName: TElem;
  props: TAtt;
};

const CreateElement: React.FC<TCreateElement> = ({ TagName, props, children }) =>
  React.createElement(TagName, props, children);

// technically this is a hoc, so would use prefix - with
// but it doesnt name well
// This existing name: TagAsComp is better describing what it is in shorthand - Tag as a component.
const TagAsComp = (TagName: TElem): React.ComponentType<any> => {
  const GetTagAsComp: React.FC<TAtt> = props => {
    const { children } = props;
    return <CreateElement {...{ TagName, props, children }} />;
  };
  return GetTagAsComp;
};

export default TagAsComp;

// Usecase:
// const Tag = TagAsComp('div')
// <Tag onClick={doThing} className="hello" data-x="extra"> Some children </Tag>

对于我的用例,我想将其传递给样式化的组件,如下所示: 看看我的其他帖子:

  const Nav = Style(TagAsComp('div'), theme);

继续查找元素上的样式化组件:

虽然上面的解决方案可以回答我最初的问题,并且可能对其他用例也很有帮助。

我现在希望它更优雅:

const StyleNav = (props: TTheme): StyledComponent<'nav', {}> => styled.nav`
  background: ${props.grey1};
  display: block;
`;