3
votes

I'm trying to create a wrapper for my styled component but I'm having trouble getting the types right.

Let's say I have a styled component like this:

const Button = styled.button<ButtonProps>`
  background-color: ${(props) => props.color};
`;

Now I want to create a wrapper component that contains this styled button, eg. like this:

const WrappedButton: React.FunctionComponent<ButtonProps> = ({ children, ...rest }) => (
  <div>
    <Button {...rest}>{children}</Button>
  </div>
);

Now this all works fine, but what I actually want is the WrappedButton component to accept all props that the Button component would accept and pass them along to the wrapped Button component.

So for example I want this to compile, as type is a valid prop of a HTML button element (and therefore also a valid prop of the Button component, but not when the Button component is wrapped):

// TypeScript will throw an error because "type" is not a valid prop of WrappedButton. 
const MyComponent = () => <WrappedButton type="submit">Test</WrappedButton>

I know I can make "type" a prop of the WrappedComponent, but that's not the point, I want the WrappedComponent to accept all props that a normal HTML button would accept.

EDIT: Also I need all styled-component specific props on the wrapped component, such as the as prop of styled-components. Here's an updated version of the code sandbox: https://codesandbox.io/s/react-typescript-styled-components-forked-3o20j?file=/src/index.tsx

I have tried so many things but TypeScript is always complaining. I have also searched the docs and the internet but have not found anything.

1

1 Answers

2
votes

I believe You are asking about React.ButtonHTMLAttributes<HTMLButtonElement>.

import React from 'react'
import styled from 'styled-components'

const Button = styled.button<ButtonProps>`
  background-color: ${(props) => props.color};
`;


type ButtonProps = {
} & React.ButtonHTMLAttributes<HTMLButtonElement>;


const WrappedButton: React.FunctionComponent<ButtonProps> = ({ children, ...rest }) => (
    <div>
        <Button {...rest}>{children}</Button>
    </div>
);

If you want to use raw html <button>, you mignt be interested in: JSX.IntrinsicElements["button"];

Check this answer

UPDATE The quick and dirty solution would be :

type ButtonProps = {
} & React.ButtonHTMLAttributes<HTMLButtonElement> & { as?: string | React.ComponentType<any> };

But it is not generic.

There is StyledComponentPropsWithAs type in SC typings, but it is not exported (