javascript - Especificar props específicos y aceptar props generales de HTML en una aplicación React con Typescript
Tengo un Componente Wrapper de React, que acepta algunas props, pero reenvía todas las demás al componente hijo (especialmente relevante para props nativas como className, id, etc.).
Sin embargo, Typescript se queja cuando paso props nativos. Ve el mensaje de error:
TS2339: La propiedad 'className' no existe en el tipo 'IntrinsicAttributes & IntrinsicClassAttributes
& Readonly<{ children?: ReactNode; }> & Readonly '.
¿Cómo puedo obtener un componente con props específicas que también acepte props nativas (sin aceptar ningún prop y renunciar a la verificación de tipos)?
Mi código se ve así:
interface WrapperProps extends JSX.IntrinsicAttributes {
callback?: Function
}
export class Wrapper extends React.Component<WrapperProps>{
render() {
const { callback, children, ...rest } = this.props;
return <div {...rest}>
{children}
</div>;
}
}
export const Test = () => {
return <Wrapper className="test">Hi there</Wrapper>
}
Para tu información: encontré una pregunta similar aquí, pero la respuesta básicamente abandona la verificación de tipos, lo cual quiero evitar: Enlace a la pregunta de SO
Respuesta #1
Podemos ver cómo se definen las propiedades de div:
interface IntrinsicElements {
div: React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>;
}
Si usamos React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement> como el tipo base, tendremos todas las propiedades de div. Dado que DetailedHTMLProps solo añade ref a React.HTMLAttributes<HTMLDivElement>, podemos usar solo esto como la interfaz base para obtener todas las propiedades de div:
interface WrapperProps extends React.HTMLAttributes<HTMLDivElement> {
callback?: Function
}
export class Wrapper extends React.Component<WrapperProps>{
render() {
const { callback, children, ...rest } = this.props;
return <div {...rest}>
{children}
</div>;
}
}
export const Test = () => {
return <Wrapper className="test">Hi there</Wrapper> // works now
}
Respuesta #2
Echa un vistazo a ComponentProps, ComponentPropsWithRef y ComponentPropsWithoutRef: esto aceptará una entrada genérica que puede ser "div", "button" o cualquier otro componente. También incluirá props específicos de React como className:
import React, {
forwardRef,
ComponentPropsWithoutRef,
ComponentProps,
ComponentPropsWithRef
} from "react";
const ExampleDivComponent = forwardRef<
HTMLDivElement,
ComponentPropsWithoutRef<"div">
>(({ children, ...props }, ref) => {
return (
<div {...props} ref={ref}>
{children}
</div>
);
});
<ExampleDivComponent
className=""
style={{ background: "green" }}
tabIndex={0}
onTouchStart={() => alert("touched")}
/>;
const ExampleButtonComponent: React.FC<ComponentProps<"button">> = ({
children,
...props
}) => {
return <button {...props}>{children}</button>;
};
<ExampleButtonComponent onClick={() => alert("clicked")} />;
