The following snippet gives me a type error:
useEffect(() => {
if(!dragWrapperRef || !dragWrapperRef.current) return;
setTimeout(() => {
setDragWrapperHeight(dragWrapperRef.current.getBoundingClientRect().height + 'px');
},500);
},[]);
current: HTMLDivElement | null. 'dragWrapperRef.current' is possibly 'null'.
const dragWrapperRef: RefObj | null = useRef(null);
type RefObj = {
current: HTMLDivElement | null
}
The type for dragWrapperRef is correctly inferred if I use dragWrapperRef.current outside of setTimeout. This does not throw an error:
useEffect(() => {
if(!dragWrapperRef || !dragWrapperRef.current) return;
setDragWrapperHeight(dragWrapperRef.current.getBoundingClientRect().height + 'px')
},[]);
It does work inside setTimeout if I assign the ref object to another variable outside of the setTimeout ((property) current: HTMLDivElement):
useEffect(() => {
if(!dragWrapperRef || !dragWrapperRef.current) return;
const el = dragWrapperRef.current;
setTimeout(() => {
setDragWrapperHeight(el.getBoundingClientRect().height + 'px')
},1000);
},[]);
Why is the type not recognized inside the scope of setTimeout if I pass it in directly – but behaves correctly if assigned to another variable?
Because things could have changed in the half-second between when you did the checks and the time the timer fires. (In the more general case: TypeScript doesn't try to track type narrowing of properties/variables that can change into callbacks. This is just a specific example.)
To avoid the error, you could assign to a local const (but keep reading):
useEffect(() => {
const current = dragWrapperRef?.current;
if (current) {
setTimeout(() => {
setDragWrapperHeight(current.getBoundingClientRect().height + "px");
}, 500);
}
}, []);
...but TypeScript is right, in the half-second between grabbing the value and the timer callback running, the ref could have changed! Meaning the code would be using an out-of-date ref. Since that's the case, you might want to just repeat the check:
useEffect(() => {
if (dragWrapperRef?.current) {
setTimeout(() => {
const current = dragWrapperRef?.current;
if (current) {
setDragWrapperHeight(current.getBoundingClientRect().height + "px");
}
}, 500);
}
}, []);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With