Search code examples
reactjstypescripttypescript-typingsreact-propstypescript-types

TypeScript: Interface cannot simultaneously extends two types


I'm writing a React app using TypeScript. I use material-ui for my components. I'm writing a custom wrapper for material-ui's Button component. It looks like this:

import MUIButton, { ButtonProps } from "@material-ui/core/Button";
import withStyles, { WithStyles } from "@material-ui/core/styles/withStyles";
import classNames from "classnames";
import React, { PureComponent } from "react";
import styles from "./styles";

export interface OwnProps {
  color: "primary" | "danger" | "warning" | "transparent";
  size: "sm" | "lg";
}

export interface Props
  extends WithStyles<typeof styles>,
    OwnProps,
    ButtonProps {}

export class Button extends PureComponent<Props> {
  render() {
    const { color, size, classes, children, ...rest } = this.props;
    const btnClasses = classNames({
      [classes.button]: true,
      [classes[size]]: size,
      [classes[color]]: color
    });
    return (
      <MUIButton {...rest} className={btnClasses}>
        {children}
      </MUIButton>
    );
  }
}

export default withStyles(styles)(Button);

The problem is that here that the definition of Props throw the error message:

Named property 'color' of types 'OwnProps' and 'ButtonProps' are not identical.
[ts]
Interface 'Props' cannot simultaneously extend types 'OwnProps' and 'ButtonProps'.
  Named property 'size' of types 'OwnProps' and 'ButtonProps' are not identical.
Named property 'color' of types 'OwnProps' and 'ButtonProps' are not identical.
[ts]
Interface 'Props' cannot simultaneously extend types 'OwnProps' and 'ButtonProps'.
  Named property 'size' of types 'OwnProps' and 'ButtonProps' are not identical.

This error goes away if I instead write:

export class Button extends PureComponent<Props & ButtonProps> {

But then when using the Button the props color and size throw the error:

The expected type comes from property 'color' which is declared here on type 'IntrinsicAttributes & Pick<Props & ButtonProps, ...

How can I correctly tell the component that it has the the Props I defined (OwnProps) as well as the props that come from the Button as usual?


Solution

  • Use TypeScript's Omit type to exclude specific properties from another type:

    Constructs a type by picking all properties from Type and then removing Keys (string literal or union of string literals).

    import { ButtonProps } from "@material-ui/core/Button";
    
    export type OwnProps = Omit<ButtonProps, "color" | "size"> & {
      color: "primary" | "danger" | "warning" | "transparent";
      size: "sm" | "lg";
    }
    
    class MyButton extends React.Component<OwnProps> {
    }