首页 > 解决方案 > 基于Generic类型的条件方法参数

问题描述

我正在编写一个新的 TypeScript 类,它采用一个通用值,该值将用作函数的输入。如果未给出值,则该函数不应接受任何输入。

理想情况下,类会像这样重载。

class Emitter<T = void> {
    public activate(): void // When T is void
    public activate(arg: T): void // When T isn't void
    public activate(arg?: T) { /* ... */ }
}

让方法成为函数属性在理论上是可行的,但需要@ts-ignore方法的实现。

type OneArgFn<T> = T extends void
    ? () => void
    : (arg: T) => void

interface Emitter<T> {
    readonly activate: OneArgFn<T>
}

另一种可能性是在提供或不提供 Generic 时导出不同的构造函数,例如以下

interface EmitterNoArg extends Emitter {
    activate: () => true
}
interface EmitterOneArg<T> extends Emitter<T> {
    activate: (arg: T) => void
}

interface EmitterConstructor {
    new(): Emitter

    new(): EmitterNoArg
    new<T>(): EmitterOneArg<T>
}

但是要导出它,unknown则需要关键字。

export default Emitter as unknown as EmitterConstructor

这些,似乎不是最优的。有没有一种基于泛型类型的条件参数的正确方法?我认为 TypeScript 的新条件类型可以解决这个问题。

标签: typescripttypescript-typings

解决方案


一种方法是在单独的公共签名中使用剩余参数中的元组:

type OneArgFn<T> = T extends void
    ? () => void
    : (arg: T) => void

class Emitter<T = void> {
    public activate(...a: Parameters<OneArgFn<T>>): void
    public activate(arg?: T) { /* ... */ }
}

new Emitter().activate();
new Emitter<string>().activate("") // in 3.4 argument names are preserved

推荐阅读