11

i'm trying to extend a react components props in TypeScript so that it contains all the normal html button attributes, as well as react specific stuff like ref

My understanding is that the type React.HTMLProps is what i need, (React.HTMLAttributes doesn't contain ref)

However, when trying to pass my props to a styled component the compiler complains.

My attempt Codesandbox example: https://codesandbox.io/s/cocky-cohen-27cpw

enter image description here

Samuel
  • 2,485
  • 5
  • 30
  • 40

3 Answers3

25

Couple of things.

Change the typing to:

interface Props extends React.ComponentPropsWithoutRef<'button'> {
  loading?: boolean
  secondary?: boolean
  fullWidth?: boolean
}

That should fix the issue for you. I forked your sandbox and it gets rid of the error.

There is also a SO post that this come from that you can use: Using a forwardRef component with children in TypeScript - the answer details one way but also mentions the answer 1.

rrd
  • 5,789
  • 3
  • 28
  • 36
9

Thanks to all who helped me get to the bottom of this. What i actually needed was to be able to forward refs to my underlying styled component, i achieved this in TypeScript like this:

enter image description here

Samuel
  • 2,485
  • 5
  • 30
  • 40
0

You are using the wrong attributes and SButton cannot access ref.

import React, { ButtonHTMLAttributes, DetailedHTMLProps } from "react";
import { render } from "react-dom";
import styled, { css } from "styled-components";

interface Props extends DetailedHTMLProps<ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement> {
  loading?: boolean;
  secondary?: boolean;
  fullWidth?: boolean;
}

export const Button: React.FC<Props> = p => {
  const { ref, ...buttonProps } = p;
  return <SButton {...buttonProps}>{p.children}</SButton>;
};

export const SButton = styled.button<Props>(
  p => css`
    /*  */
  `
);

render(<Button>Hello world</Button>, document.getElementById("root"));

This uses the correct ButtonHTMLAttributes for your props. SButton does not accept ref, that is why its extracted from the button props with const { ref, ...buttonProps } = p;. This will leave buttonProps will everything from p except ref. Hope this helps.

Domino987
  • 8,475
  • 2
  • 15
  • 38
  • Thing is i want to pass potential refs to the button element. i wonder how correct something like this might be ``` interface Props extends React.HTMLAttributes { loading?: boolean secondary?: boolean fullWidth?: boolean children: React.ReactNode className?: string ref?: React.Ref } ``` – Samuel Aug 09 '19 at 07:39
  • take a look at https://reactjs.org/docs/forwarding-refs.html#forwarding-refs-in-higher-order-components for forwaring refs – Domino987 Aug 09 '19 at 07:41
  • Yes! i just discovered that! - thanks for your help! – Samuel Aug 09 '19 at 07:49