Here's a minimal example o the type-safety problem:
https://codesandbox.io/s/mystifying-dream-8v7kgu?file=/src/App.tsx
const CanvasContainer = forwardRef<HTMLCanvasElement>((props, parentRef) => {
const localRef = useRef<HTMLCanvasElement>(null);
const canvasRef = parentRef ?? localRef;
useEffect(() => {
// type-safety no longer works here, see code sandbox link
console.log(canvasRef.current);
}, []);
return <canvas ref={canvasRef} />;
});
With typescript, the canvasRef
can be more than just a React.RefObject<HTMLCanvasElement>
. Why, and how can we achieve type-safety and access the .curent
value in this situation?
Note:
localRef
and parentRef
pattern was taken from Optional forwardRef that is required inside - ReactJS and appears to be a decent way of normalising optional refs sent this way.I ended up using this solution, since I am sure I only want to support normal refs or no refs at all and like the first comment of the question states (from Nikos), the ref could also be a setter function.
const CanvasContainer = forwardRef<HTMLCanvasElement>((props, parentRef) => {
if (typeof parentRef === "function") {
throw new Error(
`Only React Refs that are created with createRef or useRef are supported`
)
}
const localRef = useRef<HTMLCanvasElement>(null)
const canvasRef = parentRef ?? localRef
// ...