Description
Suggestion
π Search Terms
performance
emotion
material-ui
getKeyPropertyName
chooseOverload
instantiation
instantiate
large union
β Viability Checklist
My suggestion meets these guidelines:
- This wouldn't be a breaking change in existing TypeScript/JavaScript code
- This wouldn't change the runtime behavior of existing JavaScript code
- This could be implemented without emitting different JS based on the types of the expressions
- This isn't a runtime feature (e.g. library functionality, non-ECMAScript syntax with JavaScript output, new syntax sugar for JS, etc.)
- This feature would agree with the rest of TypeScript's Design Goals.
β Suggestion
TL:DR: Determine fast path in getKeyPropertyName()
by the count of non-primitives in unions, not just the length of unions.
I'm investigating type check / vscode completion performance issue with material-ui v5, and found this one of root causes.
(See mui/material-ui#19113 (comment) for more detail of the investigation.)
getKeyPropertyName()
is (indirectly) called from chooseOverload()
to determine argument type matches to the method signature. It has fast path (that returns undefined
) for small union with less than 10 constituents.
Currently it checks only one of: "length of union" OR "existence of non-primitive":
if (types.length < 10 || getObjectFlags(unionType) & ObjectFlags.PrimitiveUnion) {
This causes eager instantiation of large union type with many primitives + few non-primitives. For example it affects material-ui v5 (mui/material-ui#19113 (comment)) and emotion (emotion-js/emotion#2257).
While I'm not tested with emotion itself, both are using almost the same type. Profiler result of getDiagnostics() when editing the file contains styled()
call of material-ui v5 (with some optimization) will looks like this:
This is because they have 10-12 constitutions in the union.
export type InterpolationPrimitive = // length: 10
| null
| undefined
| boolean // true | false
| number
| string
| ComponentSelector
| Keyframes
| SerializedStyles
| CSSObject;
export type Interpolation<Props> = // length: 12
| InterpolationPrimitive
| ArrayInterpolation<Props>
| FunctionInterpolation<Props>;
Removing 3 items from InterpolationPrimitive
will remove getKeyPropertyName()
entry from above profiler result and improves performance (In above environment 170-210ms to <= 20ms).
But it'll break library feature.
So, in getKeyPropertyName()
, count non-primitive constitutions instead of length can improve performance for primitives-rich unions.
π Motivating Example
Improves type check performance when you have large union with many primitives.
π» Use Cases
See above.