Search code examples
reactjstypescripttslintreact-three-fiber

TS2532 - Object is possibly undefined - useRef and react-three-fiber


I'm implementing a component with react-three-fiber that looks like this:

const Controls = (props: any) => {
        const controlsRef = useRef();
        const { camera, gl } = useThree();

        useFrame(() => controlsRef.current && controlsRef!.current!.update());
        // ^ Errors with Object is possibly 'undefined'

        useFrame(() => {
            if (controlsRef !== undefined && controlsRef.current !== undefined) {
                controlsRef.current.target = new THREE.Vector3(worldMap.length / 2 * CELL_WIDTH, 0, worldMap.length / 2 * CELL_WIDTH)
                // ^ ALSO errors with Object is possibly undefined
            }
        })

        return (
            <orbitControls
                {...props}
                ref={controlsRef}
                args={[camera, gl.domElement]}
                enableRotate
                enablePan={false}
                maxDistance={100}
                minDistance={5}
                maxPolarAngle={Math.PI / 3}
            />
        );
    };

I've tried adding:

if (controlsRef !== undefined && controlsRef.current !== undefined) {
    controlsRef!.current!.target = ...
    // Errors with target does not exist on type 'never'
}

As well as:

useFrame(() => controlsRef.current && controlsRef?.current?.update());
// Errors with update does not exist on type 'never'

Alas to no avail. I feel like I'm bashing my head against an immovable Typescript wall!

What am I doing wrong?

(Can create a code sandbox if needed)


Solution

  • You will need to provide the types for useRef's genetic type parameter, and initialise it as null.

    const controlsRef = useRef<OrbitControls>(null);
    

    I am not sure the exact interface/typing to use as I am unfamiliar with the library you are working with, but this is the general idea.

    In addition, in your useEffect hook, it will be sufficient to use optional chaining (provided if you are working with TypeScript 3.7.5 and above)

    useFrame(() => controlsRef?.current?.update());