Search code examples
reactjstypescriptautocompletewebstorm

React. Autocomplete typing does not work when using ComponentPropsWithoutRef


I use this structure to be able to use the Avatar as any ElementType

interface AvatarOwnProps {
    className?: string
    src?: string
    alt?: string
    color?: AvatarColor
    theme?: AvatarTheme
    size?: AvatarSize
}

type AvatarProps<T extends ElementType = 'div'> = {
    as?: T
} & ComponentPropsWithoutRef<T> & AvatarOwnProps

export const Avatar = memo(<T extends ElementType = 'div'>(props: AvatarProps<T>) => {
    ...

    return (
        <Component className={classNames(cls.Avatar, {}, additional)} {...other}>
            <img src={initialSrc} alt={alt} />
        </Component>
    )
}

And when I try to use autocomplete, only my types (AvatarOwnProps) are displayed, but if I manually write for example onClick, TypeScript doesn't complain and everything works as it should. It's not critical as I can still put in the attribute I want on my own, but could this be a problem in my code? I am using WebStorm to write the code

What I see when I autocomplete


Solution

  • The problem was quite obvious, when I re-built a similar structure for another component I noticed that the autocomplete was working. Unlike the Avatar component, memo() was not used in it. Having removed it from the code, everything really worked as it should.
    Here's what it might look like:

    interface AvatarProps<T extends ElementType = 'div'> {
        className?: string
        src?: string
        as?: T
        alt?: string
        color?: AvatarColor
        theme?: AvatarTheme
        size?: AvatarSize
    }
    
    type Props<T extends ElementType> = AvatarProps<T> & Omit<ComponentPropsWithoutRef<T>, keyof AvatarProps<T>>
    
    export const Avatar = <T extends ElementType = 'div'>(props: Props<T>) => {
        const {
            as: Component = 'div',
            ...
        } = props
    
        return (
            <Component>
                ...
            </Component>
        )
    }