Skip to content
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

[TypeScript] Error when using the component-property on Buttons with react-router-dom #13218

Closed
2 tasks done
Schleuse opened this issue Oct 12, 2018 · 4 comments · Fixed by #15382
Closed
2 tasks done
Labels
component: button This is the name of the generic UI component, not the React module! typescript

Comments

@Schleuse
Copy link

Schleuse commented Oct 12, 2018

  • This is not a v0.x issue.
  • I have searched the issues of this repository and believe that this is not a duplicate.

Expected Behavior

I'm trying to use React-Router-dom with Buttons. Thankfully material-ui provides a example for this exact case in the docs.

The described approach in the docs does not seem to work properly when using Typescript. It seems that the Props of the passed Component does not widen the Props of the Button. Therefore I get a error that the passed to-Attribute does not exist in the Props of Button.

Type '{ children: string; variant: "contained"; color: "secondary"; component: typeof Link; to: string; }' is not assignable to type 'IntrinsicAttributes & ButtonProps & { children?: ReactNode; }'.
  Type '{ children: string; variant: "contained"; color: "secondary"; component: typeof Link; to: string; }' is not assignable to type 'ButtonProps'.
    Types of property 'component' are incompatible.
      Type 'typeof Link' is not assignable to type 'string | ComponentClass<ButtonProps, any> | StatelessComponent<ButtonProps> | undefined'.
        Type 'typeof Link' is not assignable to type 'StatelessComponent<ButtonProps>'.
Type '{ children: string; variant: "contained"; color: "secondary"; component: typeof Link; to: string; }' is not assignable to type 'IntrinsicAttributes & ButtonProps & { children?: ReactNode; }'.
  Type '{ children: string; variant: "contained"; color: "secondary"; component: typeof Link; to: string; }' is not assignable to type 'ButtonProps'.
    Types of property 'component' are incompatible.
      Type 'typeof Link' is not assignable to type 'string | ComponentClass<ButtonProps, any> | StatelessComponent<ButtonProps> | undefined'.
        Type 'typeof Link' is not assignable to type 'StatelessComponent<ButtonProps>'.
          Type 'typeof Link' provides no match for the signature '(props: ButtonProps & { children?: ReactNode; }, context?: any): ReactElement<any> | null'.
(JSX attribute) to: string

Steps to Reproduce

Link: https://codesandbox.io/s/8n40vqy3k0

  1. Open src/pages/index.tsx to see the error

Your Environment

Tech Version
Material-UI v3.2.0
react 16.5.2
react-dom 16.5.2
react-router-dom 4.3.1
@types/react 16.4.14
@types/react-router 4.0.32
@types/react-dom 16.0.9
@types/react-router-dom 4.3.1
TypeScript 3.1.3

tsconfig.json

{
  "compilerOptions": {
    "baseUrl": ".",
    "outDir": "build/dist",
    "module": "esnext",
    "target": "es5",
    "lib": ["es6", "dom"],
    "sourceMap": true,
    "allowJs": true,
    "jsx": "react",
    "moduleResolution": "node",
    "rootDir": "src",
    "forceConsistentCasingInFileNames": true,
    "noImplicitReturns": true,
    "noImplicitThis": true,
    "noImplicitAny": true,
    "strictNullChecks": false,
    "suppressImplicitAnyIndexErrors": true,
    "noUnusedLocals": true,
    "experimentalDecorators": true
  },
  "exclude": [
    "node_modules",
    "build",
    "scripts",
    "acceptance-tests",
    "webpack",
    "jest",
    "src/setupTests.ts"
  ]
}
@Schleuse Schleuse changed the title Type-Script Error when using the component-property on Buttons with react-router-dom [TypeScript] Error when using the component-property on Buttons with react-router-dom Oct 12, 2018
@eps1lon
Copy link
Member

eps1lon commented Oct 12, 2018

That's a current limitation of our type declarations. We would like to make them generic so that the type checker would know what additional props it can accept but we would loose argument type inference for callbacks like onChange. See #12697 and #11731.

A working solution would be the second example of the linked section (under "avoid properties collisions").

A word of advice: Try to enablestrictNullChecks. Disabled strictNullChecks can lead to errors with our type declarations and basically every other declaration under @types/.

@eps1lon eps1lon added component: button This is the name of the generic UI component, not the React module! typescript labels Oct 12, 2018
@mcabs3
Copy link

mcabs3 commented Oct 17, 2018

@Schleuse I temporarily have an ugly component (based on @eps1lon's suggestion that acts as a terrible workaround until all of this gets sorted out... anyone please feel free to improve this concept in the meantime

import * as React from "react";

import Button, { ButtonProps } from "@material-ui/core/Button";
import { Link } from "react-router-dom";
import { History } from "history";

/**
 * Issue from: https://github.com/mui-org/material-ui/issues/13218
 */

interface NavbarLinkButtonProps extends ButtonProps {
  to: History.LocationDescriptor;
  children: any;
}

const NavbarLinkButton: React.SFC<NavbarLinkButtonProps> = ({
  to,
  children,
  ...rest
}) => {
  const NavbarLink: React.SFC<any> = props => <Link to={to} {...props} />;

  return (
    <Button component={NavbarLink} {...rest}>
      {children}
    </Button>
  );
};

export default NavbarLinkButton;

// ... use case
// <NavbarLinkButton to="/home">Home</NavbarLinkButton>

@eps1lon
Copy link
Member

eps1lon commented Oct 17, 2018

@mcabs3 Could you ellaborate on why this is "ugly" or "terrible"? The only issue I can see is the any int the NavbarLink SFC and I think you might be able to replace that with ButtonProps.

I will look into this again. We could additionally export generic props and see if those are more widely adopted.

@mcabs3
Copy link

mcabs3 commented Oct 17, 2018

@eps1lon assigning a props type as ButtonProps creacted a ts error with component={NavbarLink}.

The main reason I don't like it is the fact I have to have a component definition within another component.

const NavbarLink: React.SFC<any> = props => <Link to={to} {...props} />;

Maybe I'm just being picky.

eps1lon added a commit that referenced this issue Apr 18, 2019
Component prop example was mainly concerned with react-router + button so we just added a proper demo for it.

Closes #13218
jztang pushed a commit to nyu-ossd-s19/material-ui that referenced this issue Apr 21, 2019
Component prop example was mainly concerned with react-router + button so we just added a proper demo for it.

Closes mui#13218
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: button This is the name of the generic UI component, not the React module! typescript
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants