Home > Mobile >  How can I type a generic component that takes as one of its arguments a function that returns an Axi
How can I type a generic component that takes as one of its arguments a function that returns an Axi

Time:10-06

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.

Here as you can see Typescript inferred the type for args

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;
  • Related