【问题标题】:Conditional method parameters based on Generic type基于Generic类型的条件方法参数
【发布时间】:2019-09-02 21:39:55
【问题描述】:

我正在编写一个新的 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>
}

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

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 的新 conditional types 可以解决这个问题。

【问题讨论】:

    标签: typescript typescript-typings


    【解决方案1】:

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

    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
    

    【讨论】:

    • 哇,我知道你可以推断返回类型,但我什至没有想到它也可以用于参数。我希望医生提到这一点。谢谢!
    • @MoPro 文档无法涵盖所有​​内容,但这里有一个 SO 社区可以提供帮助 :)
    • 出于好奇,在此解决方案中第二次重载activate 有什么好处?有没有只有第一个是不够的情况?第一个代码可以很容易地检查if a[0] === undefined,就像第二个代码检查arg 是否未定义一样。谢谢!
    猜你喜欢
    • 2017-11-01
    • 2019-02-18
    • 2013-02-22
    • 1970-01-01
    • 2020-10-27
    • 2022-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多