Spidy
Spidy

Reputation: 39992

Typescript: Expand existing function definition

Is it possible to create a new function definition based on an existing one?

For example, I have a third-party library that has the following two functions:

declare function v1(s: string, t: string): string;
declare function v2(n: number): string;

I have a function that was written in JS but recently has been requested to add Typescript definitions. My function looks like the following:

function useId(version, ...args) {
    return generators[version](...args);
}

What I would like to do is take the existing v1 and v2 declarations and use them in my own like so:

declare function useId(v: "v1", ...v1): string;
declare function useId(v: "v2", ...v2): string;

I have not been able to find any advanced typings that cover this specific need but wanted to check before taking a longer more verbose route to adding my function definitions (given they'll be duplicates with one new parameter out front).

Upvotes: 1

Views: 789

Answers (1)

Jeff Bowman
Jeff Bowman

Reputation: 95614

As in the question "Is there ArgumentsType<T> like ReturnType<T> in Typescript?", you can use Parameters<T> and ReturnType<T> to refer to the parameters and return type of a known function T. If you type the ...args parameters with that type, it will include those parameters in your signature.

declare function useId(v: "v1", ...args: Parameters<typeof v1>):
    ReturnType<typeof v1>;
declare function useId(v: "v2", ...args: Parameters<typeof v2>):
    ReturnType<typeof v2>;

useId("v1", "s", "t");
useId("v2", 9001);

If you are doing this repeatedly, you can use a callable interface type to represent the overload. (It may otherwise be difficult to specify the overload as a union, as in the question Overloaded function type in typescript.) If you need to do this a lot, I imagine you could even use mapped types or other cleverness to represent the relationship between your wrapper and your original function(s).

interface WrapperInterface<
    V1 extends (...args: any) => any,
    V2 extends (...args: any) => any> {
  (version: "v1", ...args: Parameters<V1>): ReturnType<V1>;
  (version: "v2", ...args: Parameters<V2>): ReturnType<V2>;
}

declare const useId2: WrapperInterface<typeof v1, typeof v2>;

useId2("v1", "s", "t");
useId2("v2", 9001);

typescript playground

Upvotes: 2

Related Questions