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

4
  • Can you show us the error message ? Commented Aug 9, 2019 at 6:59
  • Yes of course, here's a codesandbox for easier debugging: codesandbox.io/s/cocky-cohen-27cpw Commented Aug 9, 2019 at 7:08
  • It's probably got to do with this issue: github.com/DefinitelyTyped/DefinitelyTyped/issues/30451 Commented Aug 9, 2019 at 7:29
  • Adding ref?: any and as?: any would resolve the type errors Commented Aug 9, 2019 at 7:30

3 Answers 3

26

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.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, this fixed the issue
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

Comments

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.

3 Comments

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<HTMLButtonElement> { loading?: boolean secondary?: boolean fullWidth?: boolean children: React.ReactNode className?: string ref?: React.Ref<HTMLButtonElement> } ```
take a look at reactjs.org/docs/… for forwaring refs
Yes! i just discovered that! - thanks for your help!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.