Jason McFarlane
Jason McFarlane

Reputation: 2175

Styled components + typescript: "as" is not assignable to type IntrinsicAttributes

I have a monorepo that contains a design-system made with styled components. In this design system I have a Heading component that takes a 'level' prop to adjust the CSS of the heading.

Heading

export interface HeadingProps extends HTMLAttributes<HTMLHeadingElement> {
    level: 'colossus' | 'uber' | 'hero' | '1' | '2' | '3' | '4' | '5'
}

export const Heading: React.FC<HeadingProps> = ({ level = '1', children, ...rest }) => {
    return (
        <HeadingStyled level={level} {...rest}>
            {children}
        </HeadingStyled>
    )
}

Usage

To use this Heading component I simply pass a level to it for the styling and the as prop to adjust what HTML is rendered.

<Heading as="h2" level="2">
    Header 2
</Heading>

Problem

When I use this component I get a typescript error on the as prop

Type '{ children: string; as: string; level: "2"; }' is not assignable to type 'IntrinsicAttributes & HeadingProps & { children?: ReactNode; }'.

Property 'as' does not exist on type 'IntrinsicAttributes & HeadingProps & { children?: ReactNode; }'.

I have tried:

export interface HeadingProps extends HTMLAttributes<HTMLHeadingElement> {
    level: 'colossus' | 'uber' | 'hero' | '1' | '2' | '3' | '4' | '5'
    as?: React.Element | JSX.Element | JSX.IntrinsicElements
}

Upvotes: 7

Views: 6337

Answers (2)

Snainer
Snainer

Reputation: 336

in completion to @Aron's answer , this code working for me (styled-component + styled-system)

{ as?: ComponentType<any> | keyof JSX.IntrinsicElements | string | undefined }

Upvotes: 0

Aron
Aron

Reputation: 9258

You're close! JSX.IntrinsicElements is an interface whose keys are the labels of the HTML tags. It itself is not a union of all HTML tags.

That means that all you need to do is

interface HeadingProps extends HTMLAttributes<HTMLHeadingElement> {
    // ...
    as?: keyof JSX.IntrinsicElements // Note the keyof!
}

Now as's signature is shown by TS as:

(JSX attribute) HeadingProps.as?: "symbol" | "object" | "a" | "abbr" | "address" | "area" | "article" | "aside" | "audio" | "b" | "base" | "bdi" | "bdo" | "big" | "blockquote" | "body" | "br" | "button" | "canvas" | ... 156 more ... | undefined

Which means your code will now work exactly as expected

<Heading as="h2" level="2"> // No TS errors! ✅
    Header 2
</Heading>

TS playground link

Upvotes: 8

Related Questions