-
-
Notifications
You must be signed in to change notification settings - Fork 32.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Slider] onChange Typing is broken if wrapping Slider Component and reexporting Props #20191
Comments
@riceboyler The change you are referring to is #20110. I can reproduce the issue. |
Same problem if we set |
@eps1lon I would expect the Material-UI components to intercepts the incoming props and to spread props compatible with the default component. In this context, this diff seems appropriate: diff --git a/packages/material-ui/src/OverridableComponent.d.ts b/packages/material-ui/src/OverridableComponent.d.ts
index 172d3572a..14f997b70 100644
--- a/packages/material-ui/src/OverridableComponent.d.ts
+++ b/packages/material-ui/src/OverridableComponent.d.ts
@@ -21,7 +21,7 @@ export type OverrideProps<
C extends React.ElementType
> = (
& BaseProps<M>
- & Omit<React.ComponentPropsWithRef<C>, keyof CommonProps<M>>
+ & Omit<React.ComponentPropsWithRef<C>, keyof BaseProps<M>>
);
/** What do you think about it? It does break an existing test case, but looking closely at this test, I don't think that the test was correct: As far as I know, the component could very well transform the type of its input props before applying them to the root element. So, the incompatibility shouldn't be verified between the expected props and the component props, but between the default component props and the provided component props. I doubt it's something we can test, happy to ignore this case. |
This is another reason why polymorphic components are so hard to reason about. Imagine your What would be the correct type of The test you linked tests exactly that: The fix should tell typescript "I take any props that
What happens if another component is passed? We can't determine the expected type at runtime. And we don't want to always assume the type like we're using the |
@eps1lon Definitely a hard problem 🤯, here is how far I went with the reflection:
The correct type is a
Yes, we don't have enough information to conclude what
Well, it's the root of this problem (that impacts a couple of others), The
I'm not sure that we should care. Does the proposed fix match your requirements? It basically says, if you provide a custom component, we only type check the new props. |
Which means unsound types in your custom component. If you expect a non-nullable So we definitely should have this test in place. The custom component has to expect the same type or none at all. For the Slider case we simply need to tell the type checker that the underlying |
We actually have this exact same issue with the Slider as well. Previously, the Honestly, I'm glad that it was reproducible and I'm not crazy. I guess most people who use the library don't wrap the components, but we do that so we can easily pass through styling (or other props) for consistency. |
@eps1lon It's somewhat a larger issue. it impacts:
@riceboyler Do you have an example we can look at? |
I'm glad you asked. In looking back through our code, I realized that the problem was we weren't properly instantiating our The first issue with the SliderProps still applies though. |
Good news: The suggested type was definitely wrong on our part. We're not creating a custom, react change event in the Slider component. We're simply passing along whatever event triggered the change in value. I won't go into detail what specific type of events this could be so that we're not needlessly restricting our implementation. It's a bit unfortunate since it's highly unlikely that you ever relied on specifics of I suggest using |
Hey all, Error
|
It was solved in v5.0.0-alpha.1 |
AHHHH!!! We are still running v4.11. Will update and try again. Thanks! |
Is there any chance of getting this backported to a patch for 4.11? |
@rmehlinger It's unlikely, I think that we should invest time in making the upgrade easier instead rather than making it less compelling. |
For those still on v4.x, this worked for me: const MySlider: OverridableComponent<SliderTypeMap<{}, 'span'>> = (props) =>
<Slider {...props} onChange={(evt, val) => console.log(val)}/> |
Thanks @joshkarges. import React from 'react'
import MuiSlider, { SliderTypeMap } from '@material-ui/core/Slider'
import { SliderProps as MuiSliderProps } from '@material-ui/core/Slider'
import { OverridableComponent } from '@material-ui/core/OverridableComponent'
import Typography from '@material-ui/core/Typography'
interface SliderProps extends Omit<MuiSliderProps, 'onChange'> {
/**
* The label of the slider
*/
label?: string
}
export const Slider: OverridableComponent<SliderTypeMap<SliderProps, 'span'>> =
(props: SliderProps) => {
const { label, ...restProps } = props
return (
<>
{label && (
<Typography variant="body1">
{label}
</Typography>
)}
<MuiSlider {...restProps} />
</>
)
} |
We try to document the solution of this problem in https://mui.com/guides/composition/#with-typescript, not sure if it's enough. |
Since @material-ui/core v4.9.5, the Slider component appears to not be wrappable due to the change in the Typings, especially for the onChange prop.
Current Behavior 😯
When attempting to wrap and re-export a Slider component, the onChange prop now appears to be typed as
((event: React.ChangeEvent<{}>, value: number | number[]) => void) & ((event: React.FormEvent<HTMLSpanElement>) => void)
. The latter part of that Typing (the& ((event: React.FormEvent<HTMLSpanElement>) => void)
effectively breaks any function being passed into the onChange prop, as it would seem that a function can't satisfy both types here. As a result, there are TypeScript errors with onChange.Expected Behavior 🤔
I believe the typing for onChange should be just the part preceding the &, that is the
(event: React.ChangeEvent<{}>, value: number | number[]) => void
. That would allow for standard change handlers to be passed through.Steps to Reproduce 🕹
https://codesandbox.io/s/goofy-chatterjee-1hz7t
Steps:
onChange
event is marked as invalid. The full error text from TS isType '(_: any, value: any) => void' is not assignable to type '((event: ChangeEvent<{}>, value: number | number[]) => void) & ((event: FormEvent<HTMLSpanElement>) => void)'. Type '(_: any, value: any) => void' is not assignable to type '(event: FormEvent<HTMLSpanElement>) => void'.ts(2322)
Context 🔦
I'm trying to upgrade our project from 4.8.3 to 4.9.7 to stay up to date, but this issue has caused me to be unable to move forward, as I can't seem to define onChange events that will pass TS scrutiny. (FWIW, everything works as it should as far as functionality, this is just some weird typing issue.)
Your Environment 🌎
The text was updated successfully, but these errors were encountered: