Alex Gourlay
Alex Gourlay

Reputation: 385

Typing a function identically to another function with Typescript

I am wrapping a function from a library and want the wrapper function to have the same typing as the wrapped function, so that the generics and arguments can be passed through.

The function I am looking to wrap is from the apollo library, named useQuery.

It's declaration looks like this:

export declare function useQuery<TData = any, TVariables = OperationVariables>(query: DocumentNode | TypedDocumentNode<TData, TVariables>, options?: QueryHookOptions<TData, TVariables>): QueryResult<TData, TVariables>;

I want to write a function that wraps useQuery as so:

function wrapper<*generics*>(*args*) {
    ...
    return useQuery<*generics*>(*args*);
}

Can I somehow provide the generics and arguments without having to import the appropriate types?

Can this be done implicitly?

Upvotes: 4

Views: 966

Answers (2)

smac89
smac89

Reputation: 43078

It should be possible to do this. Typescript provides a set of utility types which makes this type of function wrapping, possible.

function wrapper(...args: Parameters<typeof useQuery>) {
  // Do something here
  return useQuery(...args);
}

See Parameters. You may also be interested in ReturnType.

ReturnType wasn't used in the solution because typescript is able to infer the return type provided return useQuery (...) is the last thing returned in the function.

Upvotes: 0

jcalz
jcalz

Reputation: 327819

There's not currently a way to do this in TypeScript if wrapper is declared as a function statement. You can get the type of useQuery with the typeof type operator, generics and all... but you can't annotate the whole function statement as conforming to it; you'd have to annotate the parameters and return type separately, and the generics explicitly. There is a feature request at microsoft/TypeScript#22063 asking for support for such function statement annotations, but for now they're not part of the language.

On the other hand, if you are okay declaring wrapper as a variable or constant with a function-typed value, then you can do this easily like this:

const wrapper: typeof useQuery = (...args) => {
  // do other stuff here
  return useQuery(...args);
}

There's no explicit, manual typing of the generics, parameters, or return types here. And it compiles with no error, indicating that the compiler contextually infers args to be a rest parameter of the proper generic type, and that the function returns a value of the proper generic type.

Playground link to code

Upvotes: 3

Related Questions