How can I achieve something like this?
interface Props {
result: <type of function with a lot of generic>
data: <type of one of the generics in the function above>
}
I've found a question that sounds similar here, but I'm such a newbie and not sure if this applies to my case.
The background:
I'm using react-query, and want to make a wrapper component that takes a react-query result object and a component, then shows spinner or the given component based on the query state (isLoading, isSuccess etc), whatever the query response data type is.
import React from 'react'
import {useQuery} from 'react-query'
interface WrapperProps {
result: <type of react query result>;
render: (data: <type of query data>) => React.ReactNode;
}
const Wrapper: React.FC<WrapperProps> = ({result, render}) => {
if (result.isLoading) {
return <div>spinner</div>
}
if (result.isSuccess) {
return render(result.data)
}
return <div>otherwise</div>
}
const App: React.FC = () => {
const responseString = useQuery(
['string']
async () => Promise.resolve("string")
)
const responseNumber = useQuery(
['number']
async () => Promise.resolve(3)
)
return (
<div>
<Wrapper
result={responseString}
render={(data) => (<div>successfully loaded string {data}</div>)} // <= want the data to be type string
/>
<Wrapper
result={responseInt}
render={(data) => (<div>successfully loaded int {data}</div>)} // <= want the data to be type number
/>
</div>
)
}
*1 the type of useQuery
is something like this
CodePudding user response:
You were close. You need to update Wrapper
component a bit.
First of all, you need to get rid FC
. Instead you need to add extra generic type to infer query result.
Consider this example:
import React from 'react'
import { useQuery, UseQueryResult } from 'react-query'
interface WrapperProps<T> {
result: UseQueryResult<T, unknown>
render: (data: T) => JSX.Element;
}
const Wrapper = <T,>({ result, render }: WrapperProps<T>) => {
if (result.isLoading) {
return <div>spinner</div>
}
if (result.isSuccess) {
return render(result.data)
}
return <div>otherwise</div>
}
const App: React.FC = () => {
const responseString = useQuery(
['string'],
async () => Promise.resolve("string")
)
const responseNumber = useQuery(
['number'],
async () => Promise.resolve(3)
)
return (
<div>
<Wrapper
result={responseString}
render={(data /** string */) => (<div>successfully loaded string {data}</div>)}
/>
<Wrapper
result={responseNumber}
render={(data /** number */) => (<div>successfully loaded int {data}</div>)}
/>
</div>
)
}
Please keep in mind that it is impossible to infer component props with extra generic and FC
explicit type.
Please be aware that TS since 2.9 supports explicit generics for react components