I am using typescript, react, and framer-motion.
I created a Counter component whose number increases dynamically.
However, I got a few ts errors.
Type '() => void' is not assignable to type 'undefined'.ts(2322) error occurs in place ①.
The error Cannot invoke an object which is possibly 'undefined'.ts(2722) occurs at the place ②.
export const Index: React.FunctionComponent = () => {
return (
<Counter valueTo={30} totalDuration={2 + 0.5} />%
);
};
import { useEffect, useRef, useState } from 'react';
interface Props {
valueFrom: number;
valueTo: number;
totalDuration: number;
}
export const Counter: React.FunctionComponent<Props> = ({ valueFrom = 0, valueTo = 100, totalDuration = 1 }) => {
const [count, setCount] = useState(valueFrom);
useInterval(() => {
if (count < valueTo) {
setCount(count + 1);
}
}, (totalDuration / valueTo) * 1000);
return count;
};
const useInterval = (callback: () => void, delay: number) => {
const savedCallback = useRef();
// Remember the latest callback.
useEffect(() => {
// ①
savedCallback.current = callback;
}, [callback]);
// Set up the interval.
useEffect(() => {
function tick() {
// ②
savedCallback.current();
}
if (delay !== null) {
const id = setInterval(tick, delay);
return () => clearInterval(id);
}
}, [delay]);
};
You need to declare the ref to have that type (useRef uses generics) AND make sure that the function is not undefined (useRef has "current" as undefined by default). You can do this by: (see your marked spots)
const useInterval = (callback: () => void, delay: number) => {
const savedCallback = useRef<()=>void>();
// Remember the latest callback.
useEffect(() => {
// ①
savedCallback.current = callback;
}, [callback]);
// Set up the interval.
useEffect(() => {
function tick() {
// ②
savedCallback.current && savedCallback.current();
}
if (delay !== null) {
const id = setInterval(tick, delay);
return () => clearInterval(id);
}
}, [delay]);
};