Reputation: 21048
I would like to be able to alias a very generic function and specify part of the generic parameters, thus creating a less generic version of the same function. Something like the following:
function veryGeneric<X, Y>(someParam: Y): { result: X } {
// ...
}
type LessGeneric = typeof veryGeneric<X, string>
const lessGeneric: LessGeneric = veryGeneric
Where I would want the lessGeneric
function to essentially be typed as:
function lessGeneric<X>(someParam: string): { result: X } {
// ...
}
Is this possible in any way?
I know I could create a wrapper function, but I would prefer to not have to specify the parameter typings again (and not having to pay the overhead of another function call, even if it’s tiny, would be a bonus).
Here’s the real example I’m dealing with. Given a function declaration (from react-tracking) like the following:
declare function track<T = {}, P = {}>(trackingInfo?: TrackingInfo<T, P>, options?: Options<Partial<T>>): Decorator
I want to be able to define an alias that specifies the trackingInfo
parameter’s typing but leaves P
generic. i.e. I want an alias that’s essentially typed as:
interface ValidAnalyticsEntries {
page: string
action: string
}
declare function trackSpecificToOurAnalyticsSchema<P = {}>(trackingInfo?: TrackingInfo<ValidAnalyticsEntries, P>, options?: Options<Partial<ValidAnalyticsEntries>>): Decorator
Upvotes: 5
Views: 3141
Reputation: 330316
You can do this:
const lessGeneric: <X>(someParam: string) => { result: X } = veryGeneric;
I'm just spelling out the desired type of lessGeneric
without trying to force TypeScript to convert the type of veryGeneric
to the type of lessGeneric
first. There's no wrapper function, though.
Does this work for you? If not, please add more detail to your use case and example. Specifically, the X
parameter is almost impossible to implement (how can the implementation get its hands on a value of type X
) and the Y
parameter is doing next to nothing (the someParam
argument is of type Y
, but nothing else is using Y
, so you might as well just declare someParam
to be of type any
and not use Y
).
Hope that helps; good luck!
EDIT: My suggestion for the real example looks like:
const trackSpecificToOurAnalyticsSchema: <P = {}>(
trackingInfo?: TrackingInfo<ValidAnalyticsEntries, P>,
options?: Options<Partial<ValidAnalyticsEntries>>)
=> Decorator = track;
Or, abstracting away from ValidAnalyticsEntries
:
type PartiallySpecifiedTrack<T = {}> = <P = {}>(
trackingInfo?: TrackingInfo<T, P>,
options?: Options<Partial<T>>)
=> Decorator
const trackSpecificToOurAnalyticsSchema:
PartiallySpecifiedTrack<ValidAnalyticsEntries> = track;
Note that in all these cases you still have to write out function signature at least two times in total: once when you define the fully generic track()
, and once to define PartiallySpecifiedTrack
. But you can re-use PartiallySpecifiedTrack
with different values for T
if you want:
const anotherTrack: PartiallySpecifiedTrack<{ foo: string }> = track;
declare const trackingInfo: TrackingInfo<{ foo: string }, {bar: number}>
anotherTrack(trackingInfo); // okay
Okay, that's the best I can do. Good luck!
Upvotes: 2
Reputation: 38046
To define generic type alias you can define an interface describing your function signature:
interface VeryGeneric<X, Y> {
(someParam: Y): { result: X };
}
type Foo = { foo: number };
type LessGeneric<X = Foo> = VeryGeneric<X, string>;
const lessGeneric: LessGeneric = veryGeneric;
Upvotes: 4