eps1lon/types-react-codemod

Remove deprecated `ReactHTML` and `ReactSVG`

Opened this issue · 2 comments

ReactHMTL and ReactSVG were related to createFactories but we found usage using it as a list of possible built-in browser element types.

We now have HTMLElementType and SVGElementType which can be used instead of keyof ReactHTML and keyof ReactSVG respectively.

Needs real world codebase with usage to test on.

Previously to type <motion.div /> components and props we had:

type UnwrapFactoryAttributes<F> = F extends DetailedHTMLFactory<infer P, any>
    ? P
    : never
type UnwrapFactoryElement<F> = F extends DetailedHTMLFactory<any, infer P>
    ? P
    : never

type HTMLAttributesWithoutMotionProps<
    Attributes extends HTMLAttributes<Element>,
    Element extends HTMLElement
> = { [K in Exclude<keyof Attributes, keyof MotionProps>]?: Attributes[K] }

export type HTMLMotionProps<TagName extends keyof ReactHTML> =
    HTMLAttributesWithoutMotionProps<
        UnwrapFactoryAttributes<ReactHTML[TagName]>,
        UnwrapFactoryElement<ReactHTML[TagName]>
    > &
        MotionProps

export type HTMLMotionComponents = {
    [K in HTMLElements]: ForwardRefComponent<
        UnwrapFactoryElement<ReactHTML[K]>,
        HTMLMotionProps<K>
    >
}

Which I've attempted to replace with

interface HTMLElements {
    a: HTMLAnchorElement
    abbr: HTMLElement
    address: HTMLElement
    /** etc **/
}

type AttributesWithoutMotionProps<Attributes> = {
    [K in Exclude<keyof Attributes, keyof MotionProps>]?: Attributes[K]
}

export type HTMLMotionProps<Tag extends keyof HTMLElements> = MotionProps &
    AttributesWithoutMotionProps<DOMAttributes<HTMLElements[Tag]>> &
    AttributesWithoutMotionProps<HTMLAttributes<HTMLElements[Tag]>>

export type HTMLMotionComponents = {
    [Tag in keyof HTMLElements]: ForwardRefComponent<
        HTMLElements[Tag],
        HTMLMotionProps<Tag>
    >
}

But this hasn't proven to be a direct replacement - <motion.button disabled /> will flag for errors.

This is quite a complex change and keyof ReactHTML -> HTMLElementType isn't enough, do you have an idea how this would be properly migrated?

Ah - I got it. The replacement for the props is

AttributesWithoutMotionProps<JSX.IntrinsicElements[Tag]>

And the whole thing can be replaced with

AttributesWithoutMotionProps<Attributes> = {
    [K in Exclude<keyof Attributes, keyof MotionProps>]?: Attributes[K]
}

export type HTMLMotionProps<Tag extends HTMLElementType> =
    AttributesWithoutMotionProps<JSX.IntrinsicElements[Tag]> & MotionProps

export type HTMLMotionComponents = {
    [Tag in HTMLElementType]: ForwardRefComponent<Tag, HTMLMotionProps<Tag>>
}