简体   繁体   中英

Typescript type inference for function parameter's return type

in my react project I declare my api requests with this pattern:

export type LoginApiResponse = {
  token: string,
  user: User
}

export function login(email: string, password: string): Promise<LoginApiResponse> {
  return AuthService.signinWithEmailAndPassword(email, password)
}

and I consume them through a custom hook

export function useApi<T, Fn extends (...args: any[]) => Promise<T>>(
  fn: Fn
) {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState();
  const execute = async (...params: Parameters<Fn>) => {

    setLoading(true);

    try {
      const result = await fn(...params);
      setLoading(false);
      return result;
    } catch (err) {
      console.warn("sideEfect execution error", err, JSON.stringify(err));
      setError(err);
      setLoading(false);
      throw (error);
    }
  };
  return { loading, execute, error };
}

with an implementation like this

const loginExecutor = useApi<LoginApiResponse, typeof api.login>(api.login)

In this way I encapsulate loading and error state for a given api request, plus I have full typing support

在此处输入图片说明

在此处输入图片说明

THE QUESTION

Now my question is: is there a way to take advantage of typescript type inference to infer the return type and parameters type of the fn function in order to be able to write

useApi(api.login)

instead of

useApi<LoginApiResponse, typeof api.login>(api.login)

While keeping the same strong typing?

I see that your example infers everything except a response. It has the following type:

const loginExecutor = useApi(login)

const loginExecutor: {
    loading: boolean;
    execute: (email: string, password: string) => Promise<unknown>;
    error: string;
}

Try on TS Playground


I updated useApi to extract args and return type separarly:

export function useApi<A extends any[], T>(
  fn: (...args: A) => Promise<T>
)

So now we get following type:

const loginExecutor = useApi(login)
const loginExecutor: {
    loading: boolean;
    execute: (email: string, password: string) => Promise<LoginApiResponse>;
    error: string;
}

Try on TS Playground


Please note that my examples were tested on TS >= 4.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM