在保留道具的同时扩展React和TypeScript中的HTML元素

Jos*_*osh 20 typescript reactjs tsx

我只是无法绕过这个我想,我已经尝试了大概六次并总是求助于any...是否有合法的方式从HTML元素开始,将其包装在组件中,并将其包装在另一个组件中,HTML道具通过一切?基本上自定义HTML元素?例如,类似于:

interface MyButtonProps extends React.HTMLProps<HTMLButtonElement> {}
class MyButton extends React.Component<MyButtonProps, {}> {
    render() {
        return <button/>;
    }
} 

interface MyAwesomeButtonProps extends MyButtonProps {}
class MyAwesomeButton extends React.Component<MyAwesomeButtonProps, {}> {
    render() {
        return <MyButton/>;
    }
}
Run Code Online (Sandbox Code Playgroud)

用法:

<MyAwesomeButton onClick={...}/>
Run Code Online (Sandbox Code Playgroud)

每当我尝试这种组合时,我都会收到类似于的错误:

foo的属性'ref'不能分配给目标属性.

Eim*_*eis 49

似乎上面的答案已经过时了。

在我的例子中,我用一个功能组件包装了一个样式组件,但仍然想公开常规的 HTML 按钮属性。

export const Button: React.FC<ButtonProps &
  React.HTMLProps<HTMLButtonElement>> = ({
  children,
  icon,
  ...props
}) => (
  <StyledButton {...props}>
    {icon && <i className="material-icons">{icon}</i>}
    {children}
  </StyledButton>
);
Run Code Online (Sandbox Code Playgroud)

  • ...如果你想使用 `ref` 属性,你还需要使用 `React.forwardRef` 来包装组件。知道了。 (4认同)

小智 36

您可以更改组件的定义以允许反应html按钮道具

class MyButton extends React.Component<MyButtonProps & React.HTMLProps<HTMLButtonElement>, {}> {
    render() {
        return <button {...this.props}/>;
    }
}
Run Code Online (Sandbox Code Playgroud)

这将告诉typescript编译器你想要输入按钮道具以及'MyButtonProps'

  • 这会产生 TS 错误:类型 'string' 不可分配给类型 '"button" | “提交”| “重置”| 未定义' https://www.typescriptlang.org/play/?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wG4AoctAGxQGc64BZATwCEBXGGCAOziQAPGEl4ATRsnQwAdAGFckXqJgAeKRhkAJACpMAMgAUcYOqt0HO3PgFFqSECoB8AGjgB VAL5OP5OP7gicSQoAAoASl8A6MCkGA4ofluAIy4efncZLJgAC2A6GTATOk8AeicKaM9yTyA (6认同)
  • 这与 OP 所做的完全相同,只是语法不同吗?我认为从 `React.HTMLProps` 扩展 props 与使用 `&amp;` 运算符具有相同的效果。就我而言,这没有区别,两种类型的语法都会出现相同的编译器错误。 (3认同)
  • @AlexM 看起来界面自 3 年前以来已经发生了一些变化......这有效。https://www.typescriptlang.org/play/index.html?jsx=2#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wFgAoC4AOxiSk3STgFkBPAIQFcYYJqACjjABnOAG8KcaXBBshEMAC44AIwgQANqm​​oUAvhQpIAHpFhw0mlCLHtuvfnBN1qAEz HJ0MAHQBhXJDUSLQAPHY8fILCYgBkiMQ+9PEAEgAqLAAyAIK8UMCqPEgiIWmZSfwAotogwTAAfAA0Enp1ElIyRG70ABQAlG3kMkNwRDBcUNRwIQUOk+LeCzAAFsAi3mDRenAA9HXt0gbkekA (3认同)

Abr*_*dez 31

我总是喜欢这样做:

import React from 'react';

interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  title: string;
  showIcon: boolean;
}

const Button: React.FC<ButtonProps> = ({ title, showIcon, ...props }) => {
  return (
    <button {...props}>
      {title}
      {showIcon && <Icon/>}
    </button>
  );
};
Run Code Online (Sandbox Code Playgroud)

然后你可以这样做:

<Button
  title="Click me"
  onClick={() => {}} {/* You have access to the <button/> props */}
/>
Run Code Online (Sandbox Code Playgroud)

  • 是的,它确实。但其他答案和问题则不然。这个小细节很容易被忽略,并且错误消息也没有帮助。 (2认同)

Emi*_*Emi 11

这通过使用类型(而不是接口)对我有用:

type ButtonProps = React.ButtonHTMLAttributes<HTMLButtonElement> & {
  children: React.ReactNode;
  icon?: React.ReactNode;
};

function Button({ children, icon, ...props }: ButtonProps) {
  return (
    <button {...props}>
      {icon && <i className="icon">{icon}</i>}
      {children}
    </button>
  );
}
Run Code Online (Sandbox Code Playgroud)


cyc*_*130 8

这就是我在扩展原生元素时所做的:

import React, { ButtonHTMLAttributes, forwardRef } from "react";

export interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
    myExtraProp1: string;
    myExtraProp2: string;
}

export const Button = forwardRef<HTMLButtonElement, ButtonProps>(
    ({ myExtraProp1, myExtraProp2, ...props }, ref) => (
        <button
            {...props}
            ref={ref}
            // Do something with the extra props
        />
    ),
);

Button.displayName = "Button";
Run Code Online (Sandbox Code Playgroud)

forwardRefref确保您在使用组件时可以获得对底层 HTML 元素的引用。


Dan*_*oke 6

最简洁的方法

这是我每次想要扩展 HTML 元素时使用的方法。

import { JSX } from 'react';

type ButtonProps = JSX.IntrinsicElements['button']
type DivProps = JSX.IntrinsicElements['div']
Run Code Online (Sandbox Code Playgroud)


小智 5

import * as React from "react";

interface Props extends React.HTMLProps<HTMLInputElement> {
  label?: string;
}

export default function FormFileComponent({ label, ...props }: Props) {
  return (
    <div>
      <label htmlFor={props?.id}></label>
      <input type="file" {...props} />
    </div>
  );
}
Run Code Online (Sandbox Code Playgroud)

  • 你不应该使用 HTMLProps https://react-typescript-cheatsheet.netlify.app/docs/advanced/patterns_by_usecase/#definitely-not-reacthtmlprops-or-reacthtmlattributes (2认同)