Samuel
Samuel

Reputation: 2635

TypeScript: Extend React component props for styled component element

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

Upvotes: 11

Views: 15108

Answers (3)

Samuel
Samuel

Reputation: 2635

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

Upvotes: 9

Domino987
Domino987

Reputation: 8804

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.

Upvotes: 0

rrd
rrd

Reputation: 5977

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.

Upvotes: 26

Related Questions