Skip to content

[typescript] Type portability for components extended with react-redux #3937

@cgatian

Description

@cgatian

Repro: https://stackblitz.com/edit/bf5bx4pd-epzkeps4?file=src%2Fbutton.tsx

Ask a question

Note

Appologies in advance, I'm sure the topic of TypeScript portable types is messy, but I was hoping since I've seen the team address this in other issues they might have ideas what could be going wrong.

I created a CustomButton component that extends the Base UI Button.

import { Button as BaseButton } from '@base-ui/react';

export const CustomButton: React.FC<CustomButton.Props> = (props) => {
    return <BaseButton {...props}/>
}

export declare namespace CustomButton {
   export interface Props extends BaseButton.Props;
}

When consumers of CustomButton attempt to extend with their own implementation they receive a portablity issue.

interface ProductButtonProps extends Omit<CustomButton.Props, 'onClick'> {
  product: string;
  onClick: (product: string) => void;
}

const ProductButton = ({ product, onClick, ...props }: ProductButtonProps) => {
  const handleOnClick = () => {
    onClick(product);
  };

  return (
      <CustomButton onClick={handleOnClick} {...props}>
        {product}
      </CustomButton>
  );
};

const mapDispatchToProps = {
  onClick: (product: string) => actions.toggleProductTracking({ product }),
};

// ⚠️ TS Error here
export default connect(null, mapDispatchToProps)(TrackingButtonWithLabel);

The inferred type of 'default' cannot be named without a reference to '../../../../../../../node_modules/@base-ui/react/esm/utils/types'. This is likely not portable. A type annotation is necessary.ts(2742)

Any ideas would be welcomed. Thank you 😄

Edit

I think because onClick and other event handlers use WithPreventBaseUIHandler this augments the type of event handlers. Which makes them not portable for consumers not directly importing Base UI. I think my options are to:

  1. Undo the Base UI wrapped event handlers using only the Native React event handler types
  2. Explicitly type the component with React.ComponentPropsWithoutRef<'button'> and only expose Base UI props I want consumers to know about.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions