function App(){
const cntEl:any = React.useRef(null); // I don't know what type should be here.
React.useEffect(()=>{
if(cntEl.current){ cuntEl.current.start() }
}, []);
return <Countdown ref={cntEl} />
}
const Countdown = React.forwardRef((props,ref) => {
React.useImperativeHandle(ref, ()=>({
start() {
alert('Start');
}
});
return <div>Countdown</div>
});
I try to use a child method in a parent component using ref and React.useImperativeHandle().
It works well.
but I am not satisfied because of const cntEl:any.
I believe there are many ways to avoid using any type I don't know.
I just need a type that could be replaced type any.
Edited
I can see (property) React.MutableRefObject<null>.current: null when I hover at cntEl.current
There is no need to type cntEl as any. In addition, you can use Countdown as the type generic parameter for useRef
const cntEl = React.useRef<Countdown>(null);
I recommend you use type definitions more explicitly
For example, with React DT, you can define ref exotic component with ForwardRefRenderFunction instead of FC.
type CountdownProps = {}
type CountdownHandle = {
start: () => void,
}
const Countdown: React.ForwardRefRenderFunction<CountdownHandle, CountdownProps> = (
props,
forwardedRef,
) => {
React.useImperativeHandle(forwardedRef, ()=>({
start() {
alert('Start');
}
});
return <div>Countdown</div>;
}
export default React.forwardRef(Countdown);
and then use React utility ElementRef, TypeScript can infer exact ref type of your component
const App: React.FC = () => {
// this will be inferred as `CountdownHandle`
type CountdownHandle = React.ElementRef<typeof Countdown>;
const ref = React.useRef<CountdownHandle>(null); // assign null makes it compatible with elements.
return (
<Countdown ref={ref} />
);
};
The accepted answer is overcomplicated, you just need to declare a CountdownHandle type.
For me it'll go like this:
// Countdown.tsx
export type CountdownHandle = {
start: () => void;
};
type Props = {};
const Countdown = React.forwardRef<CountdownHandle, Props>((props, ref) => {
React.useImperativeHandle(ref, () => ({
// start() has type inferrence here
start() {
alert('Start');
},
}));
return <div>Countdown</div>;
});
// The component uses the Countdown component
import Countdown, { CountdownHandle } from "./Countdown.tsx";
function App() {
const countdownEl = React.useRef<CountdownHandle>(null);
React.useEffect(() => {
if (countdownEl.current) {
// start() has type inferrence here as well
countdownEl.current.start();
}
}, []);
return <Countdown ref={countdownEl} />;
}