Jamie Hutber
Jamie Hutber

Reputation: 28086

Typescript error with styled-components and AS TS2769: No overload matches this call

I would like a simple component that I can style and pass a prop the output element type with as. Using version 5 of styled-components and 4 for TS

However I get the following TS error

TS error

No overload matches this call.
  Overload 1 of 2, '(props: Omit<Omit<Pick<DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>, "key" | keyof HTMLAttributes<...>> & { ...; }, never> & Partial<...>, "theme"> & { ...; } & { ...; }): ReactElement<...>', gave the following error.
    Type 'string' is not assignable to type 'undefined'.
  This JSX tag's 'children' prop expects type 'never' which requires multiple children, but only a single child was provided.  TS2769

    11 |     color: #000;
    12 |   `
  > 13 |   return <Component as={as}>{children}</P>
       |          ^
    14 | }
    15 |

The key part of this error is here I believe Type 'string' is not assignable to type 'undefined'. However my understanding was that with the {as = 'p'} this was the default value for as?

Component

import React, { ReactChildren } from 'react'
import styled from 'styled-components'

export interface TextProps {
  as?: string
  children?: ReactChildren | React.ReactNode | string
}

export const Text = ({ as = 'p', children }: TextProps) => {
  const Component = styled.p`
    color: #000;
  `
  return <Component as={as}>{children}</Component>
}

Upvotes: 3

Views: 6799

Answers (1)

aleksxor
aleksxor

Reputation: 8340

This one is kind of tricky. First of all, to type correctly Component accepting as prop you should give it correct typing for that as-component. And the second problem is string is wide enough to result in never type for any other props of <Component as={as as string}>. Including children prop. So one has to narrow the type of as for at least known html tags (as soon as you're allowing to pass only strings there and not custom react components).

So your code may be rewritten as:

import React, { ReactChildren } from 'react'
import styled from 'styled-components'

type KnownTags = keyof JSX.IntrinsicElements

export interface TextProps {
    as?: KnownTags
    children?: ReactChildren | React.ReactNode | string
}

export const Text = ({ as = 'p', children }: TextProps) => {
    const Component = styled.p`
        color: #000;
    `

    return <Component<typeof as> as={as}>{children}</Component>
}

Upvotes: 4

Related Questions