1

i've written a custom hook to help me not repeat code for some fetch calls. it looks like this:

export const useCustomQuery = ({ endpoint, body, dataPoint }: args) => {
    const [data, setData] = useState()
    useEffect(() => {
        fetch(`http://localhost:4000/${endpoint}`, {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body,
        })
            .then((res) => res.json())
            .then((res) => {
                if (dataPoint) {
                    setData(JSON.parse(res.data[dataPoint]))
                }
            })
    }, [endpoint, body, dataPoint])

    return { data }
}

but I'm getting some TS errors complaining about the type of data. is it possible to pass in the type as an argument as it might be different for each component that calls the hook? or what is the best way to approach this?

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
Red Baron
  • 7,181
  • 10
  • 39
  • 86
  • Yes, you can use a [generic type parameter](https://www.typescriptlang.org/docs/handbook/2/generics.html) and then either pass a type argument or allow TypeScript to infer it (if it can). *(Commenting rather than answering as I assume there's a canonical question we can point this question at...)* – T.J. Crowder Jan 12 '22 at 11:49
  • 1
    boom. Generics. perfect, thanks bro – Red Baron Jan 12 '22 at 11:54
  • Offtopic. This implementation has tons of issues because you do not cancel state updates that most likely wont be observable in dev env but would definitely hit you in production. Consider component got unmounted before the response came back. Or even worse if subsequent requests come out of order. – Yury Tarabanko Jan 12 '22 at 12:02
  • Check this question as an example https://stackoverflow.com/questions/64393441/react-hook-dependencies-generic-fetch-hook (BTW it uses generics). – Yury Tarabanko Jan 12 '22 at 12:05
  • @YuryTarabanko yeh I need to add error handling etc – Red Baron Jan 12 '22 at 12:36

2 Answers2

7

You can use generic in this case. You can do something like this:

export const useCustomQuery = <T,>({ endpoint, body, dataPoint }: args) => {
    const [data, setData] = useState<T>()
    ...
}

This way, you are giving a type T when you call the hook useCustomQuery, that parameterized the type of data, like this:

useCustomQuery<MyType>({...})
TheTisiboth
  • 1,431
  • 1
  • 6
  • 13
0

Yes, you can use generic types, here is an example. The type of generic functions is just like those of non-generic functions, with the type parameters listed first, similarly to function declarations, you need to specify the type whenever you call the hook in different components, the type will infer in that way.

function identity<Type>(arg: Type): Type {
  return arg;
}
 
let myIdentity: <Type>(arg: Type) => Type = identity;

You can refer to this link for more information.

Ritik Banger
  • 2,107
  • 5
  • 25