[material][styles] Add optimizedTheme type feature to reduce TS instantiations - #49004
[material][styles] Add optimizedTheme type feature to reduce TS instantiations#49004siriwatknp wants to merge 2 commits into
Conversation
Deploy previewBundle size
Check out the code infra dashboard for more information about this PR. |
|
@Janpot This PR is the alternative to the prior Typescript optimization, I think it’s cleaner. Do you think it’s worth to continue this effort? any downside you see on this approach? |
|
Interesting approach, definitely worth further investigating. How do you see this flag evolve? Should it become the default on a future major? Such that everyone needs to narrow down the override type. It'd be friction for some but faster types for all. One thing I would lean towards is to augment as little as possible, i.e. use augmentation for interface TypeFeatures {
optimizedTheme: true;
}but suggest components: {
// ...
} satisfies Pick<Components<Theme>, 'MuiButton' | 'MuiCard'>,That brings it closer to the callsite. That is unless it brings back all those instantiations, would you mind verifying this? and maybe also if there is a difference with components: {
// ...
} satisfies Components<Theme>, |
closes #42772, closes #47099
Alternative to #47069 based on this analysis.
Summary
Type checking a custom theme forces TypeScript to instantiate the types of all components through
theme.components. In large projects this slows down type checking and can cause out-of-memory errors in CI.This PR adds an opt-in
optimizedThemetype feature. Users enable it with one module augmentation, no import changes:With the flag on,
theme.componentsbecomes a looseThemeComponentsinterface. Type safety comes back per component through augmentation:Measured with the new
test/ts-performanceworkspace against the built package (TypeScript 6.0.3):styles/root barrel importsWhy not a separate entry point (#47069)
The
stylesOptimizedentry point restores the strict types through a global module augmentation, so one import of@mui/material/stylesor@mui/materialanywhere in the program disables the optimization. Dependencies (MUI X, Toolpad, theme libraries) make this unavoidable for most real apps. Measured: one 2-line file importingcreateTheme({})fromstylestakes the pristine program from 187 back to 145k instantiations.The flag is immune to this: it is not tied to import paths, so stray imports and dependencies cannot turn it off. It also keeps a single
Theme/ThemeOptionsidentity, so existing ecosystem augmentations of@mui/material/styleskeep working, and no mirror entry point or codemod is needed.For Reviewers
TypeFeaturesandThemeComponentsare declared increateThemeNoVars.d.ts, following the same pattern as the existingCssThemeVariablestoggle.Components<...>(Theme/ThemeOptions,CssVarsThemeOptions,ThemeWithProps) now go throughResolvedComponents<T>, a conditional type that picksThemeComponentswhen the flag is on. Conditional type branches are lazy, so the strict branch is never instantiated in optimized mode. With the flag off, resolution is identical to today (verified: same instantiation count).components.tsstill imports every component's props), so parse time remains. The instantiation explosion, which is what causes the OOM, is removed.themeCssVarsAugmentation.test/ts-performanceruns afterrelease:buildin CI (newTest theme type instantiationsstep). A shared fixture customizing every component is checked by two projects: the strict one asserts default strictness with@ts-expect-errorand reports the >100k baseline; the optimized one enables the flag, imports from the root barrel, fails above 20k instantiations, and asserts the selectiveMuiButtonaugmentation still rejects invalid values so a silently dropped augmentation fails CI.To test locally:
pnpm --filter "@mui/material..." build pnpm --filter @mui-internal/test-ts-performance test:performance