javascript - Usando el prop "as" de styled components con typescript
Actualmente estoy construyendo una biblioteca de patrones en la que he creado un componente Button usando React y styled-components. Basándome en el componente Button, quiero que todos mis componentes Link se vean exactamente igual y reciban exactamente las mismas props. Para ese propósito, estoy usando la prop as de styled-components, que me permite usar ese elemento ya construido como otra etiqueta o componente.
Componente de Botón
import * as React from 'react'
import { ButtonBorderAnimation } from './ButtonAnimation'
import { ButtonProps, ButtonVariant } from './Button.types'
import { ButtonBase, LeftIcon, RightIcon } from './Button.styled'
function Button({
variant = ButtonVariant.Filled,
children,
leftIcon = null,
rightIcon = null,
...props
}: ButtonProps): JSX.Element {
return (
<ButtonBase variant={variant} {...props}>
{variant !== ButtonVariant.Ghost ? (
<ButtonBorderAnimation {...props} />
) : null}
{leftIcon ? <LeftIcon>{leftIcon}</LeftIcon> : null}
{children}
{rightIcon ? <RightIcon>{rightIcon}</RightIcon> : null}
</ButtonBase>
)
}
export default Button
Tipos de Botones
export interface ButtonProps {
children: React.ReactNode
variant?: 'filled' | 'outlined' | 'ghost'
size?: 'small' | 'regular'
underlinedOnHover?: boolean
leftIcon?: React.ReactNode
rightIcon?: React.ReactNode
inverse?: boolean
}
export enum ButtonVariant {
Filled = 'filled',
Outlined = 'outlined',
Ghost = 'ghost',
}
export enum ButtonSize {
Small = 'small',
Regular = 'regular',
}
Componente de enlace
import * as React from 'react'
import Button from '../Button/Button'
import { Link as LinkRouter } from 'react-router-dom'
import { LinkProps } from './Link.types'
function Link({ to, ...props }: LinkProps): JSX.Element {
return <Button to={to} as={LinkRouter} {...props} />
}
export default Link
Tipos de enlace
import { ButtonProps } from '../Button/Button.types'
import { LinkProps } from 'react-router-dom'
type RouterLinkWithButtonProps = ButtonProps & LinkProps
export interface LinkProps extends RouterLinkWithButtonProps {}
Cuando hago lo anterior, este problema nos aparece...
Property 'to' does not exist on type 'IntrinsicAttributes & ButtonProps'.
...lo cual tiene sentido porque el botón no tiene la propiedad to que es requerida para el componente Link de react-router-dom.
¿Cómo abordarías algo como esto? Donde al usar el Button la propiedad to ni siquiera debería estar en el tipo y al usar el Link la propiedad to debería ser obligatoria.
Usos
<Button>Hello</Button>
<Link to="/somewhere">Hello</Link>
Respuesta #1
Esto debería funcionar.
function Link(_props: LinkProps): JSX.Element {
const props = { as: LinkRouter, ..._props };
return <Button {...props} />
}
Tenga en cuenta que TypeScript aplica verificaciones estrictas de asignación de literales de objetos, las cuales pueden relajarse asignando un literal de objeto a una variable previamente en lugar de pasarlo directamente, por ejemplo, como argumento de una función, lo cual es consistente con el comportamiento de asignación de props en componentes de React.
declare function foo(arg: { a: number }): void;
foo({ to: '', a: 1 }); // error
const arg = { to: '', a: 1 };
foo(arg); // no error
