skip to Main Content

I have a component that takes one fixed prop and one that can be random. When it comes to typing the component, I’d want to play it type safe and avoid just using any for the addition props. Here’s what I have in mind:

App.tsx:

<Button component='button' href='x'>
    Push Me
</Button>

Button.tsx:

import { type PropsWithChildren, type ElementType, type FC } from 'react';

interface ButtonProps {
    component: ElementType;
    [key: string]: any;
}

export const Button: FC<PropsWithChildren<ButtonProps>> = ({
    component: Component,
    children,
    ...props
}) => {
    return <Component {...props}>{children}</Component>;
};

How can I remove the any from [key: string] and infer the additional props?

2

Answers


  1. give a try to following .

    import { PropsWithChildren, ElementType, FC, HTMLAttributes } from 'react';
    
    interface ButtonProps extends Omit<HTMLAttributes<HTMLElement>, 'component'> {
      component: ElementType;
    }
    
    export const Button: FC<PropsWithChildren<ButtonProps>> = ({
      component: Component,
      children,
      ...props
    }) => {
      return <Component {...props}>{children}</Component>;
    };
    

    and let me know if any ?

    Login or Signup to reply.
  2. If nesting the props under an object is allowed, then this works pretty well:

    import type {ComponentProps, ElementType} from "react";
    
    type ButtonProps<T extends ElementType<any>> = {
        component: T,
        props: ComponentProps<T>,
    };
    
    export const Button = <T extends ElementType<any>>({
        component: Component,
        props,
    }: ButtonProps<T>) => {
        return <Component {...props} />
    };
    
    const MyComponent = (props: {a: number, b: number}) => {
        return <p>{props.a} + {props.b} = {props.a + props.b}</p>
    }
    
    <Button component={MyComponent} props={{a: 4, b: 5}} />;
    
    // there is a typescript error here because 'button' doesn't support 'href'
    <Button component='button' props={{href: 'x'}}>
        Push Me
    </Button>
    

    If nesting under an object is not an option then I think you can’t get full type safety. I’ve tried hacking at it for a while with mostly no luck. It seems typescript isn’t really great at validating Omit spread types haha.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search