score:3

Accepted answer

you can keep track of the argument types if you add an extra generic parameter a extends unknown[] to both useasync & useasync, and type each occurrence of ...args with it.

the result would look something like this (i had to tweak a few null types, possibly because the code wasn't compiled with strictnullchecks):

type useasync<t, a extends unknown[]> =
  [{ result: t | null; loading: boolean; error: string }, (...args: a) => void];

export const useasync = <t, a extends unknown[]>(asyncfn: (...args: a) => promise<t>): useasync<t,a> => {
  const [loading, setloading] = usestate(false);
  const [result, setresult] = usestate<t | null>(null);
  const [error, seterror] = usestate<any>(null);

  const callback = usecallback(
    async (...args: a) => {
      try {
        setloading(true);

        const result = await asyncfn(...args);

        setresult(result);
      } catch (e) {
        seterror(e);
      } finally {
        setloading(false);
      }
    },
    [asyncfn]
  );

  return [{ result, loading, error }, callback];
};

when applied to a test function, the type of postorder has the actual argument types:

type ineworderformdata = {}

const [{ result, loading, error }, postorder] = 
  useasync(async (data: ineworderformdata, arg2: symbol) => 42);

type test = typeof postorder
// inferred type: (data: ineworderformdata, arg2: symbol) => void

typescript playground


Related Query

More Query from same tag