TypeScript允许类型别名指定泛型吗?

4

我希望能够为一个非常通用的函数创建别名,并指定通用参数的某些部分,从而创建一个不那么通用的版本。类似于以下内容:

function veryGeneric<X, Y>(someParam: Y): { result: X } {
  // ...
}

type LessGeneric = typeof veryGeneric<X, string>
const lessGeneric: LessGeneric = veryGeneric

我希望lessGeneric函数的类型定义如下:

function lessGeneric<X>(someParam: string): { result: X } {
  // ...
}

有没有任何方法可以做到这一点?

我知道我可以创建一个包装函数,但我更喜欢不必再次指定参数类型(即使只是微小的开销,也不必进行另一个函数调用,这将是一个额外的优势)。


这是我正在处理的真实示例。给定一个函数声明(来自react-tracking),如下所示:

declare function track<T = {}, P = {}>(trackingInfo?: TrackingInfo<T, P>, options?: Options<Partial<T>>): Decorator

我希望能够定义一个别名,指定 trackingInfo 参数的类型,但让 P 保持泛型。也就是说,我希望这个别名的类型实际上是:

interface ValidAnalyticsEntries {
  page: string
  action: string
}

declare function trackSpecificToOurAnalyticsSchema<P = {}>(trackingInfo?: TrackingInfo<ValidAnalyticsEntries, P>, options?: Options<Partial<ValidAnalyticsEntries>>): Decorator

这里的意义是什么?X 泛型约束没有被使用,它为什么在那里?请分享您真实的代码。 - Nitzan Tomer
我认为在这个例子中不需要知道X的作用,但我添加了一个简单的插图。 - alloy
如果您更好地描述您的问题,那么您可以获得更好的帮助,而在这种情况下,它并没有被很好地解释。如果您只在函数中使用X,并且它不是参数或返回类型,则无需将其作为通用约束。 - Nitzan Tomer
我理解您的意思,但是我认为 // ... 部分表明了与问题无关的细节。现在我已经添加了真实的示例。 - alloy
你会使用相同的函数(track)还是实际上要实现trackSpecificToOurAnalyticsSchema - Nitzan Tomer
trackSpecificToOurAnalyticsSchema 常量应该保存与 track 相同的函数对象引用,因此它将是相同的函数,但在我们的代码中,我将使用 trackSpecificToOurAnalyticsSchema 常量来利用特定的类型。这回答了你的问题吗? - alloy
2个回答

4

要定义通用类型别名,您可以定义描述函数签名的接口:

interface VeryGeneric<X, Y> {
    (someParam: Y): { result: X };
}

type Foo = { foo: number };
type LessGeneric<X = Foo> = VeryGeneric<X, string>;

const lessGeneric: LessGeneric = veryGeneric;

谢谢!我仍然需要使用包装函数,以便让较不通用的版本的用户指定“X”,但至少消费者可以重复使用接口并生成具有自定义默认值的函数。您可以在此处找到这些示例 https://github.com/artsy/reaction/blob/7bc53212a5898dd02b5e49e258c932c3768d12f0/src/utils/track.ts - alloy

2
你可以这样做:
const lessGeneric: <X>(someParam: string) => { result: X } = veryGeneric;

我只是在阐述所需的 lessGeneric 类型,而不试图强制TypeScript将 veryGeneric 的类型首先转换为 lessGeneric 的类型。没有包装函数,但它可以正常工作。

如果这个方案不适合您,请提供更多使用情况和示例细节。特别是,实现几乎无法获取类型为 X 的值(实现如何获得类型为 X 的值),并且 Y 参数几乎没有发挥作用( someParam 参数的类型为 Y ,但没有其他内容使用 Y ,因此您可以声明 someParam 为类型为< code> any 并且不使用 Y )。

希望这可以帮助你,祝你好运!


编辑:我针对实际示例的建议如下:

const trackSpecificToOurAnalyticsSchema: <P = {}>(
  trackingInfo?: TrackingInfo<ValidAnalyticsEntries, P>,
  options?: Options<Partial<ValidAnalyticsEntries>>)
  => Decorator = track;

或者,抽象出ValidAnalyticsEntries

type PartiallySpecifiedTrack<T = {}> = <P = {}>(
  trackingInfo?: TrackingInfo<T, P>,
  options?: Options<Partial<T>>)
  => Decorator

const trackSpecificToOurAnalyticsSchema: 
  PartiallySpecifiedTrack<ValidAnalyticsEntries> = track;

请注意,在所有这些情况下,您仍然需要总共至少写出两次函数签名:一次在定义完全通用的track()时,一次在定义PartiallySpecifiedTrack时。但如果需要,您可以使用不同的T值重复使用PartiallySpecifiedTrack
const anotherTrack: PartiallySpecifiedTrack<{ foo: string }> = track;
declare const trackingInfo: TrackingInfo<{ foo: string }, {bar: number}>
anotherTrack(trackingInfo); // okay

好的,我能尽力而为。祝你好运!


谢谢您的建议!确实没有包装函数,所以这肯定是一个进步,但我最主要的原因是不想再次拼写所有参数。 - alloy
谢谢。我还没有找到比我上面的答案更简洁的东西。 - jcalz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接