简体   繁体   中英

Does TypeScript allow a type alias to specify generics?

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. ie 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

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;

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!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM