Reputation: 305
Suppose there is a function with multiple complex required generic types. Say there is a scenario where we want to be able to use that function over and over again, but we know that some of the generics will always be the same. Is there a way to define an intermediary function which can instead be called, which defines what those known generics are, while still allowing for other generics to be applied?
There is a function sayHello as follows:
declare function sayHello<A, B, C>(arg1: A, arg2: (arg: B) => C, /* multiple complex args... */) : C[]
Suppose I want to be able to use this function several times but most of the generics are always the same. I would think there is a way to predefine an "extension" for that function like this.
const sayNumericalHello<X> = sayHello<X,number, number>
So that it could be used repetitively with only the one generic:
sayNumericalHello<string>(/* args... */)
sayNumericalHello<number>(/* args... */)
sayNumericalHello<boolean>(/* args... */)
Is this possible? I'm fairly new to typescript, so sorry if this is basic, but I could not find any "function inheritance" like this anywhere.
Upvotes: 1
Views: 165
Reputation: 2173
One solution would be to use currying:
instead of having a function with multiple complex arg, you got a function with a single arg, that itself return a function with a single arg.
The generic type can thus be added to each level of the function appropriately.
by example :
declare function sayHello<A, B, C>(arg1: A, arg2: (arg: B) => C, /* multiple complex args... */) : C[]
could be transformed as
declare function sayHello<A>(arg1: A) : <B, C>(arg2: (arg: B) => C, /* complex args... */) => C[]
the usage become
sayHello("")((arg: number) => {})
Upvotes: 0
Reputation: 12082
You can achieve a simmilar thing by specifying default values for the B and C type variables. Since you say in most cases you want the defaults this might work for you.
declare function sayHello<A, B = number, C = number>(arg1: A, arg2: (arg: B) => C, /* multiple complex args... */) : C[];
Then you just call the method with parameters and the first type will be inferred from the parameter you pass and the others will be expected to be the default number type if you don't specify otherwise. You should not specify any type parameters when using the function for this to work else the defaults are not used and you need to specify all of them. Here are some sample calls for your scenarios.
sayHello('test', (a) => a); //string
sayHello(123, (a) => a); // number
sayHello(true, (a) => a); // boolean
Another option is to define a function with only one type parameter that calls the other more generic function this is a bit less efficient since you do another function call just that you get the signature as you want. For example:
function sayNumericalHello<A>(arg1: A, arg2: (arg: number) => number, /* multiple complex args... */) : number[] {
return sayHello(arg1, arg2, /* multiple complex args... */)
}
Upvotes: 1