Skip to content

[autocomplete] Fix TypeScript performance when using slotProps - #49634

Open
devbite-enzo wants to merge 1 commit into
mui:masterfrom
devbite-enzo:fix/autocomplete-slot-props-ts-perf
Open

devbite-enzo wants to merge 1 commit into
mui:masterfrom
devbite-enzo:fix/autocomplete-slot-props-ts-perf

Conversation

@devbite-enzo

Copy link
Copy Markdown

Same issue as #49213, in Autocomplete.

The chip, clearIndicator, paper, popper and popupIndicator slot props are typed as SlotProps<React.ElementType<Partial<XProps>>, …>. Every prop of Partial<XProps> is optional, so it fits almost every intrinsic element. React.ElementType<…> then expands to a union of ~476 HTML/SVG tags, and SlotComponentProps builds the props of each one. Whenever two different AutocompleteProps instantiations are compared, TypeScript has to measure the variance of all six type parameters through these unions. That happens with wrapper components that spread props or slotProps, which is the common pattern for form-library wrappers.

This PR types the slots by the component they render, as #49213 did for AvatarGroup. IconButton, Paper and Popper use typeof Component. chip uses React.JSXElementConstructor<Partial<ChipProps<ChipComponent>>> so it keeps the ChipComponent generic. That matches how AutocompleteSlots already types the same slots.

Performance gain

A wrapper in the usual shape:

type WrapperProps = Omit<
  AutocompleteProps<unknown, boolean | undefined, boolean | undefined, boolean | undefined>,
  'renderInput'
>;

function Wrapper({ slotProps, ...other }: WrapperProps) {
  return (
    <Autocomplete
      {...other}
      renderInput={() => null}
      slotProps={{ ...slotProps, chip: { size: 'small', ...slotProps?.chip } }}
    />
  );
}

tsc --noEmit --extendedDiagnostics on that file alone, inside packages/mui-material:

master this PR
Check time 3.39 s 1.31 s
Instantiations 2,048,830 1,778,514
Memory (RSS) 1,347 MB 813 MB

In a production Next.js app (~1,400 source files, TypeScript 7), computing the variance of AutocompleteProps took 2.9 s per checker. A full tsc --noEmit went from 20.9 s / 63 s CPU / 7.3 GB to 13.1 s / 29 s CPU / 3.0 GB with this change applied as a local patch (and --checkers 2). Since tsgo computes the variance in each checker separately, the cost multiplies with parallelism.

Compatibility

The props each slot accepts are unchanged, including component on paper. Only the props of unrelated intrinsic elements drop out of the union. The new spec cases cover the accepted props and the rejection of unknown ones. pnpm proptypes and pnpm docs:api produce no changes.

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@code-infra-dashboard

code-infra-dashboard Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Deploy preview

https://deploy-preview-49634--material-ui.netlify.app/
QR code for https://deploy-preview-49634--material-ui.netlify.app/

Bundle size

Bundle Parsed size Gzip size
@mui/material 0B(0.00%) 0B(0.00%)
@mui/lab 0B(0.00%) 0B(0.00%)
@mui/private-theming 0B(0.00%) 0B(0.00%)
@mui/system 0B(0.00%) 0B(0.00%)
@mui/utils 0B(0.00%) 0B(0.00%)

Details of bundle changes

Performance

No regressions in 32 benchmarks · ran 3m 55s · details


Check out the code infra dashboard for more information about this PR.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant