eps1lon / types-react-codemod

Collection of transforms for jscodeshift related to `@types/react`
MIT License
309 stars 11 forks source link

Remove deprecated `ReactHTML` and `ReactSVG` #362

Open eps1lon opened 6 months ago

eps1lon commented 6 months ago

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.

mattgperry commented 4 months ago

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?

mattgperry commented 4 months ago

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>>
}