Neill
Neill

Reputation: 517

React.HTMLProps<HTMLButtonElement> breaks defaultProps

I had this following code for the PropTypes of my button styled component

export type Props = {
  size?: 'small' | 'medium' | 'large',
};

StyledButton.defaultProps = {
  size: 'medium',
};

It was working fine but then I wanted to include HTMLButtonElement props to provide interactivity to my button. Therefore I added this:

export type Props = React.HTMLProps<HTMLButtonElement> & {
  size?: 'small' | 'medium' | 'large',
};

StyledButton.defaultProps = {
  size: 'medium',
};

However, this change makes defaultProps complains. This is the error, I am getting.

Types of property 'size' are incompatible.
    Type 'string' is not assignable to type 'undefined'.ts(2322)

However, If I take away the React.HTMLProps, it works, but that's not what I want. Does anybody know a solution for this?

Thanks in advance.

Upvotes: 3

Views: 5571

Answers (4)

Camilo
Camilo

Reputation: 7204

The HTMLProps type already includes a size.

I recommend using ButtonHTMLAttributes instead:

type Props = React.ButtonHTMLAttributes<HTMLButtonElement> & {
  size?: 'small' | 'medium' | 'large',
};

Upvotes: 0

Indy
Indy

Reputation: 4957

I also found that simply extending React.HTMLProps<HTMLButtonElement> does not work if you want to set custom value for size prop. Here's a solution for this problem. We're going to need small helper called Omit from utility-types package (https://github.com/piotrwitek/utility-types#omitt-k)

And use it like this:

import { Omit } from 'utility-types';

type BaseButtonProps = Omit<React.HTMLProps<HTMLButtonElement>, 'size'>;

interface ButtonProps {
  size?: 'lg' | 'sm';
}

const Button: React.FC<ButtonProps & BaseButtonProps> = ({ size }) => {
  // size is now 'lg', 'sm' or undefined
};

Upvotes: 3

Sulthan
Sulthan

Reputation: 130162

I think you have to define a new interface:

export interface Props extends React.HTMLProps<HTMLButtonElement> {
  size?: 'small' | 'medium' | 'large',
};

The problem is that React.HTMLProps or rather, its superinterface HTMLAttributes already contains a size attribute defined as:

size?: number;

Therefore, you will have to rename your property.

Upvotes: 6

rrd
rrd

Reputation: 5977

So try these, as I looked at the site https://medium.com/@martin_hotell/react-typescript-and-defaultprops-dilemma-ca7f81c661c7

type Props = Partial<DefaultProps>;

type DefaultProps = Readonly<typeof defaultProps>;

const defaultProps = {
  size: 'small' as 'small' | 'medium' | 'large';
};

export YourClass extends React.Component<Props> { }

That is the simplest easiest way, perhaps, of solving your issue, although there are others there that might help if that doesn't.

Upvotes: 0

Related Questions