I'm using TypeScript with React and am using an arrow function as a callback for a Material UI <Select> component:
import React from 'react';
import MenuItem from '@material-ui/core/MenuItem';
import Select from '@material-ui/core/Select';
interface Props {
value: string;
onSelect: (value: string) => void;
}
function MySelector(props: Props) {
return (
<Selectvalue={props.value}onChange={e => props.onSelect(e.value as string)}
>
<MenuItem value="a">A</MenuItem><MenuItem value="b">B</MenuItem><MenuItem value="c">C</MenuItem></Select>
)
}
To avoid passing down a new function every time MySelector renders, I'd like to use the useCallback hook. While a direct refactor works at runtime, it fails to type check because of an implicit any error on the event parameter, e:
function MySelector(props: Props) {
const handleChange = React.useCallback(
e => props.onSelect(e.value as string),
// ~ e implicitly has an any type
[props.onSelect]
);
return (
<Selectvalue={props.value}onChange={handleChange}
>
{ /* ... menu items ... */ }
</Select>
)
}
Mousing over the e symbol in the original shows its type as
React.ChangeEvent<{
name?: string | undefined;
value: unknown;
}>
It's a mouthful, but to fix the error that's what I have to put in:
const handleChange = React.useCallback(
(
e: React.ChangeEvent<{
name?: string | undefined;
value: unknown;
}>,
) => props.onSelect(e.value as string),
[props.onSelect],
);
Can I have my cake and eat it, too? Can I use the useCallback hook and still get the type of the event parameter from context?
Yes, you can use the useCallback hook and still get the type of the event parameter from context. To do this, you can specify the type of the event parameter as a type parameter for the callback function.
Here's how you can modify your code to use the useCallback hook and get the type of the event parameter from context:
function MySelector(props: Props) { const handleChange = React.useCallback<React.ChangeEventHandler<{value: unknown}>>( e => props.onSelect(e.value as string), [props.onSelect] ); return ( <Selectvalue={props.value}onChange={handleChange} > { /* ... menu items ... */ } </Select> ) }
By specifying the type parameter React.ChangeEventHandler<{value: unknown}>, you are telling TypeScript that the callback function is a change event handler that takes an event of type React.ChangeEvent<{value: unknown}>. This allows TypeScript to correctly infer the type of the event parameter and avoid the implicit any error.