【问题标题】:Reduce duplication when overloading functions in TypeScript在 TypeScript 中重载函数时减少重复
【发布时间】:2021-03-09 05:08:55
【问题描述】:

假设我有一个函数,它接受一个数组并将其转换为某种对象。输入数组可以是undefined,此时函数返回undefined

function toNdArray(arr: number[] | undefined): ndarray | undefined {
  return arr && ndarray(arr);
}

如果我使用number[] | undefined 类型的变量调用此函数,结果的类型为ndarray | undefined,正如预期的那样:

(arr: number[] | undefined) => {
    const result = toNdArray(arr);
    // => actual = wanted = `ndarray | undefined`
}

但是,如果我使用我确定已定义的数组调用函数,我希望结果的类型为ndarray,而不是ndarray | undefined,所以我可以使用无需强制转换(例如as ndarray)或使用类型保护(例如isDefined())即可:

const result = toNdArray([0, 1, 2]);
// => actual = `ndarray | undefined`
// => wanted: `ndarray`

一种解决方案是使用function overloading:

function toNdArray(arr:number[]): ndarray;
function toNdArray(arr:number[] | undefined): ndarray | undefined;
function toNdArray(arr: number[] | undefined): ndarray | undefined {
  return arr && ndarray(arr);
}

这很好用,但非常冗长。我觉得烦人的是必须复制toNdArray 的完整签名(即第二个重载)。如果我不指定并且仅指定第一个重载,则上面的第一个用例将不再有效,因为 TS 在重载列表中不包含 toNdArray 的实现(如 TS 文档中所述):

function toNdArray(arr:number[]): ndarray;
function toNdArray(arr: number[] | undefined): ndarray | undefined {
  return arr && ndarray(arr);
}

(arr: number[] | undefined) => {
    const result = toNdArray(arr); // TS error
}

在上面的示例中重复并不算太糟糕,但在实际示例中,在 Prettier 将长函数签名拆分为多行的项目中,它确实会使代码膨胀。我已经把代码放在in a TypeScript playground 上面,以防你想玩它。

所以我的问题如下:

  • 有没有办法在这种简单的重载场景中减少重复?
  • 是否有替代函数重载的方法可以实现相同的结果而减少膨胀?也许是条件返回类型?到目前为止,我的尝试都没有成功,但也许我做错了。

【问题讨论】:

  • "我觉得烦人的是必须复制 toNdArray 的完整签名(即第二次重载)" 但你的 second 重载 应该是function toNdArray(arr: undefined): undefined; - 这不是重复的。您的 actual 方法签名应该合并以上所有,而不是使用联合作为输入/输出 number[] | undefined。虽然您也可以只声明它们any - 真正的函数签名仍然接受上面的那些。虽然你在那里失去了一些类型安全,但这可能不是问题。
  • 按照@VLAZ提到的,这样看:每个重载签名实际上只是“如果这些参数,那么这个结果”,而实现上的签名只是为了你自己的类型安全该函数的上下文。
  • 我可以理解膨胀问题,但这是构建 TS 代码时的一个常见问题——“我希望它有多精确”与“我想为此编写多少代码”相关。在nullundefined 的示例中,您可以保留联合类型并在结果上使用“新”optional changing and nullish operators 来跳过类型保护。在其他更复杂的示例中,您要么必须为每个用例编写复杂的推断结果类型包装器,要么接受过载膨胀。
  • @Axel function toNdArray(arr: undefined): undefined 不适用于与工会。我的理解是你想说,如果传入一个数组,你会得到ndarray,如果你通过undefined,你会得到undefined。这不允许混合输入。如果您想要混合输入,那么您还需要另一个重载。这里没有更短的选择 - 这就是重载的工作方式。重载是实现这种行为的正确方式。您可以得到较短的内容,但它们会缺乏清晰度和/或正确性。

标签: typescript


【解决方案1】:

我最终找到了一个working solution,它有一个覆盖和一个条件返回类型:

function toNdArray<T extends number[] | undefined>(arr: T): T extends number[] ? ndarray : undefined;

function toNdArray(arr: number[] | undefined): ndarray | undefined {
    return arr && ndarray(arr);
}

在我最初的尝试中,我曾尝试将条件返回类型直接放在实现签名上,而不是添加覆盖。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2023-01-31
    • 1970-01-01
    • 2017-08-25
    • 2017-10-19
    • 2012-10-24
    • 1970-01-01
    相关资源
    最近更新 更多