在重载函数时,我有时会使用以下模式:

export function foo(a: string): void;
export function foo(b: number): void;
export function foo(a: string, b: number): void;
export function foo(...args: [string] | [number] | [string, number]): void {
    /* ... */
}

这使得很容易确定使用了哪种原型,例如,如果是args.length === 2,则已知args[string, number].对于更复杂的类型(假设您有两个接口,而不是stringnumber),这可以大大简化.

但是,在使用可选参数时,我无法使其正常工作:

export function foo(a?: string): void;
//              ~~~ error TS2394: This overload signature is not compatible with its implementation signature.
export function foo(...args: [] | [string]): void {
    return;
}

我知道我可以在没有可选参数的情况下简单地添加另一个重载,但组合很快就会变得无法管理.

export function foo(): void;
export function foo(a: string): void;
export function foo(...args: [] | [string]): void {
    return;
}

一个更具体的例子是:

interface Foo {
  /* ... */
}

interface Bar {
  /* ... */
}

interface Baz {
  /* ... */
}

function awesomeFunction(foo?: Foo, bar?: Bar): void;
function awesomeFunction(baz: Baz, foo?: Foo, bar?: Bar): void;
function awesomeFunction(...args:
  | [Foo | undefined, Bar | undefined]
  | [Baz, Foo | undefined, Bar | undefined]
): void {
  /* ... */
}

因为我知道,如果args[0]Baz,我也会知道args的其余元素.然而,它不能像上面看到的foo函数那样工作.

输入所有的排列将变成许多变体,而输入每个参数为arg1?: Foo | Baz, arg2: Foo | Bar, arg3: Bar意味着我必须输入判断不可能的变体.

有没有办法解决这个问题?

推荐答案

本质上是direct equivalence between function parameter lists and tuple types.特别是,(x?: string) => void中的optional function parameters Like对应于optional tuple elements Like [string?](或者,当您使用tuple element labels[x?: string]时).

这意味着您可以像这样编写您的overload个实现:

function foo(a?: string): void;
function foo(...args: [string?]): void {
}

function awesomeFunction(foo?: Foo, bar?: Bar): void;
function awesomeFunction(baz: Baz, foo?: Foo, bar?: Bar): void;
function awesomeFunction(...args: [Foo?, Bar?] | [Baz, Foo?, Bar?]): void {
}

实际上,如果所有调用签名的返回类型都相同,您甚至不需要重载:

function bar(...args: [a?: string]): void { }
// bar(a?: string | undefined): void

当您调用接受REST元组联合的函数时,它看起来像是一个重载函数:

function awesomeFunction(...args:
  [foo?: Foo, bar?: Bar] | [baz: Baz, foo?: Foo, bar?: Bar]
): void { }
// 1/2 awesomeFunction(foo?: Foo | undefined, bar?: Bar | undefined): void
// 2/2 awesomeFunction(baz: Baz, foo?: Foo | undefined, bar?: Bar | undefined): void

虽然[string?][string] | []之间的关系是有争议的,但当可选的元组元素可用时,试图强迫编译器看到它可能是没有意义的.

Playground link to code

Typescript相关问答推荐

具有映射返回类型的通用设置实用程序

类型脚本如何将嵌套的通用类型展开为父通用类型

React组件数组及其props 的类型定义

TypScript在对象上强制执行值类型时推断对象文字类型?

具有动态键的泛型类型

创建一个根据布尔参数返回类型的异步函数

使某些(嵌套)属性成为可选属性

在HighChats列时间序列图中,十字准线未按预期工作

在VSCode中显示eslint错误,但在终端中运行eslint命令时不显示?(Vite,React,TypeScript)

有没有办法取消分发元组的联合?

如何正确调用创建的类型?

Typescript 中相同类型的不同结果

TypeScrip:使用Union ToInterval辅助对象,但保留子表达式

在打字脚本中对可迭代对象进行可变压缩

try 使Angular依赖注入工作

打字:注解`是字符串`而不是`布尔`?

如何在Vue动态类的上下文中解释错误TS2345?

如何限定索引值必须与相应属性的id字段相同

如何从 Select 元素中删除选项

通用可选函数参数返回类型