LeoShi
LeoShi

Reputation: 1857

typescript interface with different number of types

I have a custom hook like this, I want to make request parameter optional and response required:

function useRequest<T, S = any>(api: (input?: S) => Promise<T>) {
  const [response, setResponse] = useState<T | null>(null);

  const fetchData = useCallback(
    (input?: S) => {
      api(input)
        .then((data) => {
          setResponse(data as T);
        })
    },
    [api],
  );
  return { response, fetchData };
}

Basically I want to call useRequest like this:

function A()
{
  //return a promise
}
function B(p1: boolean) {
  //return a promise
}

useRequest<ResponseA>(A)
useRequest<ResponseB, boolean>(B)

but I cannot use second one since the boolean is not compatible with boolean | undefined.

Upvotes: 0

Views: 54

Answers (1)

Titian Cernicova-Dragomir
Titian Cernicova-Dragomir

Reputation: 250236

You don't have to limit yourself to just one parameter, using tuples in rest parameters you can capture the type of the parameters and spread them back out to a new function. The effect of this is that the arity of the function is preserved:

import { useState, useCallback} from 'react'

function useRequest<T, P extends any[]>(api: (...params: P) => Promise<T>) {
  const [response, setResponse] = useState<T | null>(null);

  const fetchData = useCallback(
    (...params: P) => {
      api(...params)
        .then((data) => {
          setResponse(data as T);
        })
    },
    [api],
  );
  return { response, fetchData };
}


type ResponseA = { a: string }
type ResponseB = { b: string }
declare function A(): Promise<ResponseA>;
declare function B(p1: boolean): Promise<ResponseB>;

useRequest(A)
useRequest(B)

Playground Link

Upvotes: 2

Related Questions