I'm trying to create a generic component that takes a render prop and a request prop, and uses the response from that request to render components specified in its render prop. How can I type the interface for that component? So far I tried
import { AxiosResponse } from 'axios';
import { ScrollBox } from 'components/atoms';
import { IProps as ScrollBoxProps } from 'components/atoms/ScrollBox/ScrollBox';
import React, { ReactNode } from 'react';
interface IProps extends ScrollBoxProps {
request: (args?: unknown) => Promise<void | AxiosResponse<never>>;
render: (args?: unknown) => ReactNode;
}
export const FetchBox: React.FC<IProps> = ({
rounded,
title,
height,
request,
render,
}) => {
const [list, setList] = React.useState(undefined);
React.useEffect(() => {
const makeRequest = async () => {
const response = await request();
setList(response?.data.data);
};
makeRequest();
}, []);
return (
<ScrollBox rounded={rounded} title={title} height={height}>
{list?.map((element) => render(element))}
</ScrollBox>
);
};
export default FetchBox;
But if I do this, I get a type error when trying to destructure the data
key from the response data (Property 'data' does not exist on type 'never').
All of the functions passed to the request prop are going to return Axios promises. How do I go about typing that interface?
CodePudding user response:
Made a dummy example for you, Added the example in codesandbox, basically what I understand is that your Array of objects can have different types Lets say Array of Apple or Array of Oranges, and you want to generalise them.
CodePudding user response:
here is a working example. You can type directly the response of Axios (in your example I have also typed the args of the 2 functions)
import { AxiosResponse } from 'axios';
import React, { ReactNode } from 'react';
interface IProps<T, U, V> { // note the typing
request: (args?: U) => Promise< void | AxiosResponse<T>>;
render: (args?: V) => ReactNode;
}
export const FetchBox: React.FC<IProps<number, string, string>> = ({
request,
render,
}) => {
const [list, setList] = React.useState(undefined);
React.useEffect(() => {
const makeRequest = async () => {
const response = await request();
setList(response && response.data); // note the test here to handle when return type is void
};
makeRequest();
}, []);
return (
<div>
{list?.map((element) => render(element))}
</div>
);
};
export default FetchBox;