【发布时间】: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 代码时的一个常见问题——“我希望它有多精确”与“我想为此编写多少代码”相关。在
null和undefined的示例中,您可以保留联合类型并在结果上使用“新”optional changing and nullish operators 来跳过类型保护。在其他更复杂的示例中,您要么必须为每个用例编写复杂的推断结果类型包装器,要么接受过载膨胀。 -
@Axel
function toNdArray(arr: undefined): undefined不适用于与工会。我的理解是你想说,如果传入一个数组,你会得到ndarray,如果你通过undefined,你会得到undefined。这不允许混合输入。如果您想要混合输入,那么您还需要另一个重载。这里没有更短的选择 - 这就是重载的工作方式。重载是实现这种行为的正确方式。您可以得到较短的内容,但它们会缺乏清晰度和/或正确性。
标签: typescript