framer / motion

Open source, production-ready animation and gesture library for React
https://framer.com/motion
MIT License
22.27k stars 733 forks source link

[BUG] framer-motion-3d: Ref Types are incorrect #2644

Open alexbakerdev opened 2 weeks ago

alexbakerdev commented 2 weeks ago

2. Describe the bug

As Per #1732 the typescript definition for ThreeMotionComponents refs is incorrect. However, the user submitted solution in #1732 is also wrong, the ref should be typed as a @react-three/fiber component's underlying three object, and not component props.

3. IMPORTANT: Provide a CodeSandbox reproduction of the bug

Codesandbox

4. Steps to reproduce

  1. go to the codesandbox link above
  2. look at line 49 of src/CameraRig.tsx
  3. hover over the underlined ref text
  4. Observe the below error in a popover
    Type 'RefObject<PerspectiveCamera>' is not assignable to type 'Ref<PerspectiveCameraProps> | undefined'.
    Type 'RefObject<PerspectiveCamera>' is not assignable to type 'RefObject<PerspectiveCameraProps>'.
    Type 'PerspectiveCamera' is not assignable to type 'PerspectiveCameraProps'.
      Type 'PerspectiveCamera' is not assignable to type 'Omit<ExtendedColors<Overwrite<Partial<PerspectiveCamera>, NodeProps<PerspectiveCamera, typeof PerspectiveCamera>>>, NonFunctionKeys<...>>'.
        Types of property 'attach' are incompatible.
          Type '(object: Object3D<Object3DEventMap>) => PerspectiveCamera' is not assignable to type 'AttachType | undefined'.
            Type '(object: Object3D<Object3DEventMap>) => PerspectiveCamera' is not assignable to type 'AttachFnType'.
              Types of parameters 'object' and 'parent' are incompatible.
                Property 'attach' is missing in type 'Instance' but required in type 'Object3D<Object3DEventMap>'.typescript(2322)
    Object3D.d.ts(494, 5): 'attach' is declared here.
    index.d.ts(119, 9): The expected type comes from property 'ref' which is declared here on type 'IntrinsicAttributes & Omit<ThreeMotionProps & Omit<AcceptMotionValues<PerspectiveCameraProps>, "onUpdate" | "transition">, "ref"> & RefAttributes<...>'

This is because the type of that motion component's ref is React.Ref<PerspectiveCameraProps> | undefined.

5. Expected behavior

There should be no type error here, and instead the type for ref should be (property) ref?: Ref<PerspectiveCamera> | undefined.

7. Environment details

n/a

Possible Fix

The issue seems to be caused here, with presumably out of date types. https://github.com/framer/motion/blob/main/packages/framer-motion-3d/src/types.ts#L56

The types provided for the intrinsic elements by @react-three/fiber already include the correct ref. So in this case the intrinsic element for perspectiveCamera is PerspectiveCameraProps (defined by @react-three/fiber) and the ref property of that is indeed React.Ref<PerspecitveCamera>. (there are two example types at the bottom of the CameraRig module).

export type ThreeMotionComponents = {
-    [K in keyof JSX.IntrinsicElements]: ForwardRefComponent<
+    [K in keyof JSX.IntrinsicElements]: react.FunctionComponent<
-        JSX.IntrinsicElements[K],
        ThreeMotionProps &
            Omit<
                AcceptMotionValues<JSX.IntrinsicElements[K]>,
                "onUpdate" | "transition"
            >
    >
}

I've used this patch to unblock myself today, but I haven't extensively tested it.

Risks

I can't quite figure out where/when this became broken as both react-three/fiber and framer-motion-3d type files have barely changed over the last few years.

I also think perhaps fixing this will cause issues for anyone who used the workaround solution proposed in #1732. Getting new ref type errors could lead to some hair pulling.