material-ui icon indicating copy to clipboard operation
material-ui copied to clipboard

[material-ui][Alert] TS error when using slotProps with customised component

Open alexey-kozlenkov opened this issue 1 year ago • 8 comments

Steps to reproduce

Link to live example: https://codesandbox.io/p/sandbox/damp-monad-sptgfr?file=%2Fsrc%2FDemo.tsx%3A12%2C4

Steps:

  1. Check out TS error in slotProps

Current behavior

On example of Alert component (it's likely a common issue):

slots allow to customise closeIcon component to be something else the default IconButton. However, if I set it be some custom component, slotProps won't pickup prop types from defined component and keep pointing to IconButtonProps from mui package

Expected behavior

Complaint types

Context

No response

Your environment

No response

Search keywords: slot slotProps

alexey-kozlenkov avatar Jun 10 '24 10:06 alexey-kozlenkov

not found example link T^T

appleSimple avatar Jun 10 '24 14:06 appleSimple

@appleSimple my bad 😞 This one should work: https://codesandbox.io/p/sandbox/damp-monad-sptgfr?file=%2Fsrc%2FDemo.tsx%3A12%2C4

alexey-kozlenkov avatar Jun 10 '24 16:06 alexey-kozlenkov

slotProps's type could be any because of K extends Record<keyof Slots, any>, but not applied any type.

This may be related part of cause.

Alert.d.ts

export type AlertSlotsAndSlotProps = CreateSlotsAndSlotProps<
  AlertSlots,
  {
    closeButton: SlotProps<React.ElementType<IconButtonProps>, {}, AlertOwnerState>;
    closeIcon: SlotProps<React.ElementType<SvgIconProps>, {}, AlertOwnerState>;
  }
>;

types.ts

export type CreateSlotsAndSlotProps<Slots, K extends Record<keyof Slots, any>> = {
  /**
   * The components used for each slot inside.
   * @default {}
   */
  slots?: Slots;
  /**
   * The props used for each slot inside.
   * @default {}
   */
  slotProps?: {
    [P in keyof K]?: K[P];
  };
};

appleSimple avatar Jun 17 '24 04:06 appleSimple

@appleSimple any could be passed as a slotProps's value to CreateSlotsAndSlotProps, can't be passed to Alert's close button slotProps cause it's already specified as SlotProps<React.ElementType<IconButtonProps>, {}, AlertOwnerState>

alexey-kozlenkov avatar Jun 17 '24 07:06 alexey-kozlenkov

You can type cast slotProps.closeButton to resolve the issue. Here's how:

<Alert
  icon={<CheckIcon fontSize="inherit" />}
  severity="success"
  onClose={() => void 0}
  slots={{
    closeIcon: CloseIcon,
    closeButton: MyIconButton,
  }}
  slotProps={{
    closeButton: {
      iconSize: 'medium',
    } as MyIconButtonProps,
  }}
>
  Here is a gentle confirmation that your action was successful.
</Alert>

This approach works, but it's not clear if it should be documented as a solution or is considered a workaround in which case this is a bug.

ZeeshanTamboli avatar Jun 24 '24 10:06 ZeeshanTamboli

@ZeeshanTamboli I don't it's possible since slotProps values there are not just types of desired props but a SlotProps<...> wrapper around original MUI's IconButtonProps, as I specified at the beginning of that issue.

image

alexey-kozlenkov avatar Jun 24 '24 10:06 alexey-kozlenkov

Hey @alexey-kozlenkov, thanks for the report 😊

This use case is covered in other components by adding ...SlotPropsOverrides types, for example the BadgeRootSlotPropsOverrides type in the Badge component. These types can then be augmented to accomplish the expected behavior, for example: https://codesandbox.io/p/sandbox/slot-props-overrides-example-7nm889?file=%2Fsrc%2FApp.tsx%3A10%2C2.

This hasn't been implemented in all components, the Alert being one of them. I'm accepting this as an enhancement for the missing functionality and adding the ready-to-take label if anyone wishes to work on it. It should be enough to add new types AlertCloseButtonSlotPropsOverrides and AlertCloseIconSlotPropsOverrides following the pattern used in Badge.

DiegoAndai avatar Jun 28 '24 20:06 DiegoAndai

@DiegoAndai have a look please when convenient

alexey-kozlenkov avatar Jun 29 '24 17:06 alexey-kozlenkov