【问题标题】:A typescript type that allows any html attribute允许任何 html 属性的打字稿类型
【发布时间】:2020-08-21 23:42:18
【问题描述】:

我,试图创建一个模拟原生 html 元素的反应组件。

问题一:

允许有效的 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>;

错误

“字符串”类型与“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”与索引签名不兼容。 “string”类型与“HTMLAttributes”类型没有共同的属性。ts(2322)

任何帮助表示赞赏。 谢谢

【问题讨论】:

标签: reactjs typescript


【解决方案1】:

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

我确信有更好的方法,但为了保持严格,并允许将此组件传递给另一个未知的组件处理程序,我必须确保我返回了 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;
`;

【讨论】:

    猜你喜欢
    • 2021-06-09
    • 1970-01-01
    • 2016-03-21
    • 1970-01-01
    • 2019-03-10
    • 1970-01-01
    • 2019-07-11
    • 1970-01-01
    • 2018-03-27
    相关资源
    最近更新 更多