Skip to content

Typescript typings breaking when omitting props for TextField #19579

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

Closed
2 tasks done
JamieS1211 opened this issue Feb 6, 2020 · 4 comments
Closed
2 tasks done

Typescript typings breaking when omitting props for TextField #19579

JamieS1211 opened this issue Feb 6, 2020 · 4 comments
Labels
component: text field This is the name of the generic UI component, not the React module! duplicate This issue or pull request already exists typescript

Comments

@JamieS1211
Copy link
Contributor

I am making a component that forwards prop types to material UI components. When doing this with TextField I get complaints about "variant" type being incompatable.

  • The issue is present in the latest release.
  • I have searched the issues of this repository and believe that this is not a duplicate.

Current Behavior 😯

Error is given in typescript

Expected Behavior 🤔

Would expect no error and it to function in the same way as with other components such as Typography

Steps to Reproduce 🕹

https://codesandbox.io/s/material-ui-typescript-wierdness-yk119

Context 🔦

I have made custom formik inputs. In these instances props such as error, helperText etc. are set by formik hence I want to omit them to prevent intelisense suggesting them as valid props on my fields.

image

Your Environment 🌎

See codesandbox for more details

Tech Version
Material-UI v4.9.1
React 16.12.0
Browser
TypeScript 3.7.4
etc.
@eps1lon
Copy link
Member

eps1lon commented Feb 6, 2020

Thanks for opening this issue and filling out the template.

This is in essence a duplicate of #15697. More explanation and possible workaround can be found in #15697 (comment).

@eps1lon eps1lon closed this as completed Feb 6, 2020
@eps1lon eps1lon added component: text field This is the name of the generic UI component, not the React module! duplicate This issue or pull request already exists typescript labels Feb 6, 2020
@JamieS1211
Copy link
Contributor Author

Hi there, thanks for the reply and link to the other issue. While the issue defiantly appears in the same way I think there is a bit of subtle difference in the two issues. For instance in my case I am using the Omit<> type to specifically omit a unrelated key and it was the Omit<> process that was mutating the type into the manner seen in the other issue.

This was one of the reasons for it confusing me so much as I was not interacting with the variant attribute that was giving the error and I somewhat naively believed Omit<> to be perfect. Therefor I refocused my bug / issue hunting on to typescript itself and found this issue - microsoft/TypeScript#31501

In that issue the different implementations of Omit<> and their subtle differences are discussed with proposed other implementations. Using the proposed OmitBetter<> and OmitBetterStrict<> both fixed my issue.

Hope this can help anyone else in the future <3

@kgregory
Copy link
Member

I am offering this comment to help anyone who comes across this issue, as I have today.

I found my way here because I was converting a component to TypeScript that wraps a TextField with some specific props. Any props provided to the component are spread onto TextField to allow for some overrides by the consumer. For some reason I haven't entirely nailed down, this was causing a TypeScript error.

Here's a simplified reproduction of the issue I was experiencing:

// TypeScript error on `TextField`
const MyTextFieldWrapper: React.FC<TextFieldProps> = props => {
  const classes = useStyles();
  const { InputProps, ...otherTextFieldProps } = props;
  return (
     <TextField
      className={classes.textField}
      InputProps={{ disableUnderline: true, ...InputProps }}
      {...otherTextFieldProps}
    />
  );
};

...and the TypeScript error:

Type '{ onBlur?: FocusEventHandler<HTMLInputElement | HTMLTextAreaElement> | undefined; onChange?: ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement> | undefined; ... 281 more ...; InputProps: { ...; } | ... 2 more ... | { ...; }; }' is not assignable to type 'IntrinsicAttributes & TextFieldProps'.
  Types of property 'InputProps' are incompatible.
    Type '{ disableUnderline: true; } | { disableUnderline: boolean; color?: "primary" | "secondary" | undefined; translate?: "yes" | "no" | undefined; margin?: "none" | "dense" | undefined; ... 273 more ...; classes?: Partial<...> | undefined; } | { ...; } | { ...; }' is not assignable to type 'Partial<OutlinedInputProps> | undefined'.
      Type '{ disableUnderline: true; }' is not assignable to type 'Partial<OutlinedInputProps>'.
        Property 'disableUnderline' does not exist on type 'Partial<OutlinedInputProps>'.ts(2322)

(pretty, huh?)

I reasoned that TypeScript might be having trouble combining the explicit assignments and the spread props, so I tried this, and it eliminated the TypeScript error:

const MyTextFieldWrapperWithoutTheTypeScriptError: React.FC<TextFieldProps> = props => {
  const classes = useStyles();
  const { InputProps, ...otherTextFieldProps } = props;

  const wrapperProps = {
    className: classes.textField,
    InputProps: { disableUnderline: true, ...InputProps },
    ...otherTextFieldProps,
  };

  return <TextField {...wrapperProps} />;
};

I'm using @material-ui/core 4.11.4 and typescript 4.2.3. If you're experiencing something similar, I hope this helps.

@kgregory
Copy link
Member

kgregory commented Jul 14, 2021

I've had to overcome another, similar issue. This time my component composes several Material-UI components and has a prop named TextFieldProps which is spread onto the TextField it renders. My component allows variant to default, but is explicitly disabling the underline via InputProps. Since a consumer might have provided InputProps as part of TextFieldProps, we do this to ensure that the default behavior of our component is to have the underline disabled:

interface MyTextFieldProps {
  TextFieldProps?: Partial<TextFieldProps>;
}

// Typescript error on `TextField`
const MyTextField: React.FC<MyTextFieldProps> = (props) => {
  const classes = useStyles();
  const { InputProps, ...otherTextFieldProps } = props.TextFieldProps ?? {};
  return (
    <TextField
      className={classes.textField}
      InputProps={{ disableUnderline: true, ...InputProps }}
      {...otherTextFieldProps}
    />
  );
};

...and the TypeScript error:

Type '{ onBlur?: FocusEventHandler<HTMLInputElement | HTMLTextAreaElement> | undefined; onChange?: ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement> | undefined; ... 281 more ...; InputProps: { ...; } | ... 2 more ... | { ...; }; } | { ...; } | { ...; }' is not assignable to type 'IntrinsicAttributes & TextFieldProps'.
  Type '{ onBlur?: FocusEventHandler<HTMLInputElement | HTMLTextAreaElement> | undefined; onChange?: ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement> | undefined; ... 281 more ...; InputProps: { ...; } | ... 2 more ... | { ...; }; }' is not assignable to type 'IntrinsicAttributes & TextFieldProps'.
    Type '{ onBlur?: FocusEventHandler<HTMLInputElement | HTMLTextAreaElement> | undefined; onChange?: ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement> | undefined; ... 281 more ...; InputProps: { ...; } | ... 2 more ... | { ...; }; }' is not assignable to type 'OutlinedTextFieldProps'.
      Types of property 'variant' are incompatible.
        Type '"outlined" | undefined' is not assignable to type '"outlined"'.
          Type 'undefined' is not assignable to type '"outlined"'.ts(2322)

The error only occurs when I include disableUnderline: true. I am not sure why variant is being inferred as outlined here because OutlinedInputProps doesn't have disableUnderline.

I have a reproduction codesandbox for those interested (maybe @eps1lon?)

To defeat this, I decided to assign InputProps based on variant:

export const MyTextField: React.FC<MyTextFieldProps> = props => {
  const classes = useStyles();
  const { InputProps, variant = 'standard', ...otherTextFieldProps } = props.TextFieldProps ?? {};
  const TextFieldInputProps =
    variant === 'outlined' ? InputProps : { disableUnderline: true, ...InputProps };
  return (
    <TextField
      className={classes.textField}
      variant={variant}
      InputProps={TextFieldInputProps}
      {...otherTextFieldProps}
    />
  );
};

Fun times. Again, hope this helps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: text field This is the name of the generic UI component, not the React module! duplicate This issue or pull request already exists typescript
Projects
None yet
Development

No branches or pull requests

3 participants