I have a custom hook called useDropdownSelection
. It's fairly simple. Here's the code:
import { useState } from 'react'
export const useDropdownSelection = (initialValue: string) => {
const [selectedOption, setSelectedOption] = useState<string>(initialValue)
const handleClick = (event: React.MouseEvent<HTMLLIElement>) => {
const target = event.target as HTMLElement
setSelectedOption(target.innerText)
}
return [selectedOption, handleClick]
}
As you can see, the handleClick
function is of type (event: React.MouseEvent<HTMLLIElement>) => void
But when I import it to my index.tsx, the handleClick
function, for whatever reason, becomes of type string | ((event: MouseEvent<HTMLLIElement, MouseEvent>) => void)
const [selectedDropdownOption, handleDropdownClick] = useDropdownSelection('Most upvotes') // const handleDropdownClick: string | ((event: MouseEvent<HTMLLIElement, MouseEvent>) => void). WHY?
Why is this happening?
I assume it has something to do with the fact that I'm returning an array?
CodePudding user response:
If you are returning an array in your Custom Hook, you will want to avoid type inference as TypeScript will infer a union type (when you actually want different types in each position of the array).
What you need to do if you want to avoid the union type is using a const assertion:
return [selectedOption, handleClick] as const;
Now selectedOption and handleClick will keep respectively their type.
Docs: https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/hooks/#custom-hooks
CodePudding user response:
It's because you don't specify that useDropdownSelection
is going to return array of specific types for each indexes, so TS assumes that each index may contain both callback and string value.
check example below:
const f = (s: string) => {
const n: number = 5;
return [s, n];
}
const result = f('s');
result
is a (string | number)[]
type. To explicitly inform that it's going to be [string, number] you have to implement it like below:
const f = (s: string): [string, number] => {
const n: number = 5;
return [s, n];
}
const result = f('s'); // type is [string, number]
Syntax presented above is similar to one that is implemented by useState.
So in your example explicitly type return value of a hook:
export const useDropdownSelection = (initialValue: string): [string, (event: MouseEvent<HTMLLIElement, MouseEvent>) => void] => {...}